home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / adatutor / csparts / cspartb2.src < prev    next >
Text File  |  1996-01-30  |  338KB  |  10,449 lines

  1. --::::::::::
  2. --fof.bdy
  3. --::::::::::
  4. -- **********************************
  5. -- *                                *
  6. -- *  FOF_Command_Symbols           *  SPEC & BODY
  7. -- *                                *
  8. -- **********************************
  9. package FOF_Command_Symbols is
  10.  
  11. --| Purpose
  12. --| FOF_Command_Symbols contains the error messages issued by
  13. --| routines within the package body of FOF.
  14. --|
  15. --| Initialization Exceptions (none)
  16. --| Notes (none)
  17. --|
  18. --| Modifications
  19. --| 04/22/90  Rick Conn    Initial Version
  20.  
  21.   Error_Internal_Break_Line
  22.     : constant STRING
  23.       := "Internal error in FOF.Break_Line";
  24.  
  25.   Error_Internal_Break_Page_1
  26.     : constant STRING
  27.       := "Internal error in FOF.Break_Page (1st routine)";
  28.  
  29.   Error_Internal_Break_Page_2
  30.     : constant STRING
  31.       := "Internal error in FOF.Break_Page (2nd routine)";
  32.  
  33.   Error_Internal_Bottom
  34.     : constant STRING
  35.       := "Internal error in FOF.Output_Bottom_Of_Page";
  36.  
  37.   Error_Internal_Hf_Line
  38.     : constant STRING
  39.       := "Internal error in FOF.Put_Header_Footer_Line";
  40.  
  41.   Error_Internal_Pnum
  42.     : constant STRING
  43.       := "Internal error in FOF.Pnum_As_String";
  44.  
  45.   Error_Internal_Put_Invisible
  46.     : constant STRING
  47.       := "Internal error in FOF.Put_Invisible_Word";
  48.  
  49.   Error_Internal_Put_Line
  50.     : constant STRING
  51.       := "Internal error in FOF.Put_Line";
  52.  
  53.   Error_Internal_Put_What
  54.     : constant STRING
  55.       := "Internal error in FOF.Put_Word.Put_What";
  56.  
  57.   Error_Internal_Put_Word
  58.     : constant STRING
  59.       := "Internal error in FOF.Put_Word";
  60.  
  61.   Error_Internal_Set_Footer_Line
  62.     : constant STRING
  63.       := "Internal error in FOF.Set_Footer_Line";
  64.  
  65.   Error_Internal_Set_Header_Line
  66.     : constant STRING
  67.       := "Internal error in FOF.Set_Header_Line";
  68.  
  69.   Error_Internal_Skip
  70.     : constant STRING
  71.       := "Internal error in FOF.Skip";
  72.  
  73.   Error_Internal_Top
  74.     : constant STRING
  75.       := "Internal error in FOF.Output_Top_Of_Page";
  76.  
  77. end FOF_Command_Symbols;
  78. package FOF_DYN is 
  79. -- This package is derived from DSTR3.SRC in the Ada Software Repository
  80. -- DSTR3.SRC was written by R.G. Cleaveland.  The derivation, done by
  81. -- Richard Conn, was done to remove those general-purpose features of the
  82. -- package not needed for the PTF project.
  83. ------------------------------------------------------------------------------
  84. --  This is a package of several string manipulation functions based on     --
  85. -- a built-in dynamic STRING type DYN_STRING.  It is an adaptation and      --
  86. -- extension of the package proposed by Sylvan Rubin of Ford Aerospace and  --
  87. -- Communications Corporation in the Nov/Dec 1984 issue of the Journal of   --
  88. -- Pascal, Ada and Modula-2.  Some new functions have been added, and much  --
  89. -- of the body code has been rewritten.                                     --
  90. ------------------------------------------------------------------------------
  91. -- R.G. Cleaveland 07 December 1984:                                        --
  92. --  Implementation initially with the Telesoft Ada version 1.3.             --
  93. -- 06 Feb 85: CHAR changed to add the optional parameter POSIT.             --
  94. -- 06 Feb 85: procedure SUBSTITUTE added.                                   --
  95. -- 05 Apr 85: procedures UPPERCASE and CHECKBYTE added.                     --
  96. -- 04 Feb 86: style and formatting changes made, some comments fixed.       --
  97. -- Ported to VERDIX VADS (VAX Ultrix version 5.1).                          --
  98. -- 10 Feb 86: Several bugs fixed - SIZE constrained, exception for '&'      --
  99. -- generating too long a string added, error in integer conversion fixed.   --
  100. -- Functions EQUALS, ">", "<=" and ">=" added.  Subtype DS_POS incorporated.--
  101. ------------------------------------------------------------------------------
  102.  
  103.   MAX_D_STRING_LENGTH : constant POSITIVE := 100; 
  104.     -- This is the maximum LENGTH of a dynamic string implemented with this
  105.     -- package.  This value is "arbitrary" in that any reasonable number
  106.     -- equal to or less than the maximum STRING LENGTH permitted by the
  107.     -- compiler is acceptable.  The specific value above was chosen as a
  108.     -- compromise between programmer convenience and memory space requirements.
  109.  
  110.  
  111.  
  112.   subtype DS_POS is INTEGER range 0..MAX_D_STRING_LENGTH;
  113.   
  114.   type DYN_STRING is private;
  115.  
  116.   STRING_TOO_SHORT: exception;
  117.  
  118.   
  119.   
  120.   function D_STRING(CHAR: CHARACTER)  return DYN_STRING;
  121.           -- Creates a one-byte dynamic string of contents CHAR.
  122.  
  123.   function D_STRING(STR : STRING   )  return DYN_STRING;
  124.           -- Creates a dynamic string of contents STR.
  125.  
  126.   function CHAR(DSTR  : DYN_STRING;
  127.                 POSIT : POSITIVE := 1) return CHARACTER;
  128.   
  129.   function STR (DSTR: DYN_STRING) return STRING;
  130.   
  131.   function LENGTH(DSTR: DYN_STRING)     return NATURAL;
  132.     -- returns the LENGTH of the dynamic string.
  133.  
  134.   procedure CLEAR(DSTR: in out DYN_STRING);
  135.                   -- makes DSTR a null string.
  136.  
  137. private
  138.   type DYN_STRING is
  139.     record
  140.       SIZE: INTEGER range 0..MAX_D_STRING_LENGTH;
  141.       DATA: STRING(1..MAX_D_STRING_LENGTH);
  142.     end record;
  143. end FOF_DYN;
  144.  
  145.  
  146. package body FOF_DYN is
  147.            
  148.   procedure CLEAR(DSTR: in out DYN_STRING) is
  149.     
  150.     begin
  151.       DSTR.SIZE := 0;
  152.     end CLEAR;
  153.  
  154.   function D_STRING(CHAR: CHARACTER)  return DYN_STRING is
  155.           
  156.       DS : DYN_STRING;
  157.     
  158.     begin
  159.       DS.SIZE     := 1;
  160.       DS.DATA(1)  := CHAR;
  161.       return DS;
  162.     end D_STRING;
  163.   
  164.   function D_STRING(STR : STRING   )  return DYN_STRING is
  165.           
  166.       DS : DYN_STRING;
  167.     
  168.     begin
  169.       DS.SIZE                   := STR'LENGTH;
  170.       DS.DATA(1..DS.SIZE)       := STR;
  171.       return DS;
  172.     end D_STRING;
  173.   
  174.   function CHAR(DSTR  : DYN_STRING;
  175.                 POSIT : POSITIVE := 1) return CHARACTER is
  176.     
  177.     begin
  178.       if POSIT > DSTR.SIZE then 
  179.         raise STRING_TOO_SHORT;
  180.       else 
  181.         return DSTR.DATA(POSIT);
  182.       end if;
  183.     end CHAR;
  184.   
  185.   function STR (DSTR: DYN_STRING) return STRING is
  186.     
  187.     begin
  188.       return DSTR.DATA(1..DSTR.SIZE);
  189.     end STR;
  190.   
  191.   function LENGTH(DSTR: DYN_STRING) return NATURAL is
  192.     
  193.     begin
  194.       return DSTR.SIZE;
  195.     end LENGTH;
  196.   
  197. begin --(FOF_DYN)
  198.   null;
  199. exception
  200.   when others => 
  201.     raise;
  202.  
  203. end FOF_DYN;
  204. -- **********************************
  205. -- *                                *
  206. -- *  FOF_Error_Log                 *  SPEC
  207. -- *                                *
  208. -- **********************************
  209. package FOF_Error_Log is
  210.  
  211. --| Purpose
  212. --| FOF_Error_Log is used to log errors to an output file or console.
  213. --|
  214. --| Initialization Exceptions (none)
  215. --| Notes (none)
  216. --|
  217. --| Modifications
  218. --| 08/16/89  Rick Conn    Initial Version
  219.  
  220.   -- ..................................
  221.   -- .                                .
  222.   -- .  Open                          .  SPEC
  223.   -- .                                .
  224.   -- ..................................
  225.   procedure Open
  226.     ( File_Name      : in STRING );
  227.  
  228.   --| Purpose
  229.   --| Open the error log file.  If the File_Name is empty, error log
  230.   --| goes to standard output.
  231.   --|
  232.   --| Exceptions (none)
  233.   --| Notes (none)
  234.  
  235.   -- ..................................
  236.   -- .                                .
  237.   -- .  Write_Error                   .  SPEC
  238.   -- .                                .
  239.   -- ..................................
  240.   procedure Write_Error
  241.     ( Message        : in STRING );
  242.  
  243.   --| Purpose
  244.   --| Write_Error makes an error message entry into the error log file.
  245.   --|
  246.   --| Exceptions (none)
  247.   --| Notes (none)
  248.  
  249.   -- ..................................
  250.   -- .                                .
  251.   -- .  Write_Warning                 .  SPEC
  252.   -- .                                .
  253.   -- ..................................
  254.   procedure Write_Warning
  255.     ( Message        : in STRING );
  256.  
  257.   --| Purpose
  258.   --| Write_Warning makes a warning message entry into the error log file.
  259.   --|
  260.   --| Exceptions (none)
  261.   --| Notes (none)
  262.  
  263.   -- ..................................
  264.   -- .                                .
  265.   -- .  Close                         .  SPEC
  266.   -- .                                .
  267.   -- ..................................
  268.   procedure Close;
  269.  
  270.   --| Purpose
  271.   --| Close closes the error log file.
  272.   --|
  273.   --| Exceptions (none)
  274.   --| Notes (none)
  275.  
  276. end FOF_Error_Log;
  277. -- **********************************
  278. -- *                                *
  279. -- *  FOF_Output_File               *  SPEC
  280. -- *                                *
  281. -- **********************************
  282. package FOF_Output_File is
  283.  
  284. --| Purpose
  285. --| FOF_Output_File implements an abstract data type of an output file.
  286. --| FOF_Output_File offers an abstraction that can be made more efficient
  287. --| by not using Text_IO (and having its associated overhead imposed)
  288. --| if possible and also offers the ability to suppress the output,
  289. --| which may be desired if a caller is skipping over pages and just
  290. --| wants to output to a null device during this process.
  291. --|
  292. --| Initialization Exceptions (none)
  293. --| Notes (none)
  294. --|
  295. --| Modifications
  296. --| 08/16/89  Rick Conn    Initial Version
  297.  
  298.   type FILE_TYPE is
  299.     private;
  300.  
  301.   Cannot_Create_Output_File
  302.     : exception;
  303.  
  304.   Write_Error
  305.     : exception;
  306.  
  307.   -- ..................................
  308.   -- .                                .
  309.   -- .  Already_Exists                .  SPEC
  310.   -- .                                .
  311.   -- ..................................
  312.   function Already_Exists
  313.     ( File_Name      : in STRING )
  314.     return BOOLEAN;
  315.  
  316.   --| Purpose
  317.   --| Determine if the FILE_TYPE object already exists.
  318.   --|
  319.   --| Exceptions (none)
  320.   --| Notes (none)
  321.  
  322.   -- ..................................
  323.   -- .                                .
  324.   -- .  Delete                        .  SPEC
  325.   -- .                                .
  326.   -- ..................................
  327.   function Delete
  328.     ( File_Name      : in STRING )
  329.     return BOOLEAN;
  330.  
  331.   --| Purpose
  332.   --| Delete the FILE_TYPE object.  Return TRUE if successful.
  333.   --|
  334.   --| Exceptions (none)
  335.   --| Notes (none)
  336.  
  337.   -- ..................................
  338.   -- .                                .
  339.   -- .  Create                        .  SPEC
  340.   -- .                                .
  341.   -- ..................................
  342.   procedure Create
  343.     ( Id             : in out FILE_TYPE;
  344.       File_Name      : in STRING );
  345.  
  346.   --| Purpose
  347.   --| Create creates a new FILE_TYPE object.
  348.   --|
  349.   --| Exceptions
  350.   --|   Cannot_Create_Output_File
  351.   --|
  352.   --| Notes (none)
  353.  
  354.   -- ..................................
  355.   -- .                                .
  356.   -- .  Put                           .  SPEC
  357.   -- .                                .
  358.   -- ..................................
  359.   procedure Put
  360.     ( Id             : in out FILE_TYPE;
  361.       Item           : in CHARACTER );
  362.   procedure Put
  363.     ( Id             : in out FILE_TYPE;
  364.       Item           : in STRING );
  365.  
  366.   --| Purpose
  367.   --| Put writes an Item to the FILE_TYPE object.
  368.   --|
  369.   --| Exceptions
  370.   --|   Write_Error
  371.   --|
  372.   --| Notes (none)
  373.  
  374.   -- ..................................
  375.   -- .                                .
  376.   -- .  Put_Line                      .  SPEC
  377.   -- .                                .
  378.   -- ..................................
  379.   procedure Put_Line
  380.     ( Id             : in out FILE_TYPE;
  381.       Item           : in STRING );
  382.  
  383.   --| Purpose
  384.   --| Put_Line writes an Item to the FILE_TYPE object.  The Item is followed
  385.   --| by a New_Line;
  386.   --|
  387.   --| Exceptions
  388.   --|   Write_Error
  389.   --|
  390.   --| Notes (none)
  391.  
  392.   -- ..................................
  393.   -- .                                .
  394.   -- .  New_Line                      .  SPEC
  395.   -- .                                .
  396.   -- ..................................
  397.   procedure New_Line
  398.     ( Id             : in out FILE_TYPE );
  399.  
  400.   --| Purpose
  401.   --| New_Line writes an end-of-line sequence to the FILE_TYPE object.
  402.   --|
  403.   --| Exceptions
  404.   --|   Write_Error
  405.   --|
  406.   --| Notes (none)
  407.  
  408.   -- ..................................
  409.   -- .                                .
  410.   -- .  New_Page                      .  SPEC
  411.   -- .                                .
  412.   -- ..................................
  413.   procedure New_Page
  414.     ( Id             : in out FILE_TYPE );
  415.  
  416.   --| Purpose
  417.   --| New_Page writes an end-of-page sequence to the FILE_TYPE object.
  418.   --|
  419.   --| Exceptions
  420.   --|   Write_Error
  421.   --|
  422.   --| Notes (none)
  423.  
  424.   -- ..................................
  425.   -- .                                .
  426.   -- .  Enable_Output                 .  SPEC
  427.   -- .  Disable_Output                .
  428.   -- .                                .
  429.   -- ..................................
  430.   procedure Enable_Output
  431.     ( Id             : in out FILE_TYPE );
  432.   procedure Disable_Output
  433.     ( Id             : in out FILE_TYPE );
  434.  
  435.   --| Purpose
  436.   --| Enable_Output and Disable_Output enable and disable the output of
  437.   --| Items and new lines to the FILE_TYPE object.  When created, output
  438.   --| to a FILE_TYPE object is enabled.
  439.   --|
  440.   --| Exceptions (none)
  441.   --| Notes (none)
  442.  
  443.   -- ..................................
  444.   -- .                                .
  445.   -- .  Close                         .  SPEC
  446.   -- .                                .
  447.   -- ..................................
  448.   procedure Close
  449.     ( Id             : in out FILE_TYPE );
  450.  
  451.   --| Purpose
  452.   --| Close closes output to the FILE_TYPE object.
  453.   --|
  454.   --| Exceptions (none)
  455.   --| Notes (none)
  456.  
  457. private -- FOF_Output_File
  458.   type FILE_OBJECT;
  459.   type FILE_TYPE is
  460.     access FILE_OBJECT;
  461.  
  462. end FOF_Output_File;
  463. -- **********************************
  464. -- *                                *
  465. -- *  FOF_Error_Log                 *  BODY
  466. -- *                                *
  467. -- **********************************
  468. with FOF_Output_File;
  469. with TEXT_IO;
  470. package body FOF_Error_Log is
  471.  
  472. --| Notes (none)
  473. --|
  474. --| Modifications
  475. --| 08/16/89  Rick Conn    Initial Version
  476.  
  477.   Is_Open
  478.     : BOOLEAN
  479.       := false;
  480.  
  481.   Error_File
  482.     : FOF_Output_File.File_Type;
  483.  
  484.   Output_To_Stdio
  485.     : BOOLEAN
  486.       := false;
  487.  
  488.   Error_Count
  489.     : NATURAL
  490.       := 0;
  491.  
  492.   Warning_Count
  493.     : NATURAL
  494.       := 0;
  495.  
  496.   -- ..................................
  497.   -- .                                .
  498.   -- .  Open                          .  BODY
  499.   -- .                                .
  500.   -- ..................................
  501.  
  502.   procedure Open
  503.     ( File_Name      : in STRING ) is
  504.  
  505.   --| Notes (none)
  506.  
  507.   begin -- Open
  508.  
  509.     if File_Name'Length > 0 then
  510.       FOF_Output_File.Create(Error_File, File_Name);
  511.       Is_Open        := true;
  512.       Output_To_Stdio := false;
  513.     else
  514.       Is_Open        := true;
  515.       Output_To_Stdio := true;
  516.     end if;
  517.  
  518.   exception -- Open -- Open -- Open
  519.     when others =>
  520.       Is_Open        := true;
  521.       Output_To_Stdio := true;
  522.  
  523.   end Open;
  524.  
  525.   -- ..................................
  526.   -- .                                .
  527.   -- .  Write_Error                   .  BODY
  528.   -- .                                .
  529.   -- ..................................
  530.   procedure Write_Error
  531.     ( Message        : in STRING ) is
  532.  
  533.   --| Notes (none)
  534.  
  535.   begin -- Write_Error
  536.  
  537.     if not Is_Open then
  538.       Open("");
  539.     end if;
  540.     if Output_To_Stdio then
  541.       TEXT_IO.Put("FOF Error: " & Message);
  542.     else
  543.       FOF_Output_File.Put(Error_File, "FOF Error: " & Message);
  544.     end if;
  545.     Error_Count    := Error_Count + 1;
  546.  
  547.   end Write_Error;
  548.  
  549.   -- ..................................
  550.   -- .                                .
  551.   -- .  Write_Warning                 .  BODY
  552.   -- .                                .
  553.   -- ..................................
  554.   procedure Write_Warning
  555.     ( Message        : in STRING ) is
  556.  
  557.   --| Notes (none)
  558.  
  559.   begin -- Write_Warning
  560.  
  561.     if not Is_Open then
  562.       Open("");
  563.     end if;
  564.     if Output_To_Stdio then
  565.       TEXT_IO.Put("FOF Warning: " & Message);
  566.     else
  567.       FOF_Output_File.Put(Error_File, "FOF Warning: " & Message);
  568.     end if;
  569.     Warning_Count  := Warning_Count + 1;
  570.  
  571.   end Write_Warning;
  572.  
  573.   -- ..................................
  574.   -- .                                .
  575.   -- .  Close                         .  BODY
  576.   -- .                                .
  577.   -- ..................................
  578.   procedure Close is
  579.  
  580.   --| Notes (none)
  581.  
  582.   begin -- Close
  583.  
  584.     if Is_Open then
  585.       if not Output_To_Stdio then
  586.         FOF_Output_File.Close(Error_File);
  587.       end if;
  588.     end if;
  589.     TEXT_IO.Put("  ");
  590.     if Error_Count = 0 then
  591.       TEXT_IO.Put("No Errors, ");
  592.     else
  593.       TEXT_IO.Put(NATURAL'Image(Error_Count) & " Error(s), ");
  594.     end if;
  595.     if Warning_Count = 0 then
  596.       TEXT_IO.Put("No Warnings");
  597.     else
  598.       TEXT_IO.Put(NATURAL'Image(Warning_Count) & " Warning(s)");
  599.     end if;
  600.     TEXT_IO.New_Line;
  601.  
  602.   end Close;
  603.  
  604. end FOF_Error_Log;
  605. -- **********************************
  606. -- *                                *
  607. -- *  FOF_Output_File               *  BODY
  608. -- *                                *
  609. -- **********************************
  610. with Text_IO;
  611. package body FOF_Output_File is
  612.  
  613. --| Notes (none)
  614. --|
  615. --| Modifications
  616. --| 08/16/89  Rick Conn    Initial Version
  617. --| 02/26/90  Rick Conn    Fix bug in Already_Exists test
  618.  
  619.   type FILE_OBJECT is
  620.     record
  621.       File           : Text_IO.File_Type;
  622.       Is_Open        : BOOLEAN      := false;
  623.       Is_Output_Enabled : BOOLEAN   := true;
  624.     end record;
  625.  
  626.   -- ..................................
  627.   -- .                                .
  628.   -- .  Already_Exists                .  BODY
  629.   -- .                                .
  630.   -- ..................................
  631.   function Already_Exists
  632.     ( File_Name      : in STRING )
  633.     return BOOLEAN is
  634.  
  635.   --| Notes (none)
  636.  
  637.     File
  638.       : Text_IO.File_Type;
  639.  
  640.     Result
  641.       : BOOLEAN
  642.         := true;
  643.  
  644.   begin -- Already_Exists
  645.  
  646.     begin
  647.       Text_IO.Open(File, Text_IO.In_File, File_Name);
  648.       Text_IO.Close(File);
  649.     exception
  650.       when others =>
  651.         Result := false;
  652.     end;
  653.     return Result;
  654.  
  655.   end Already_Exists;
  656.  
  657.   -- ..................................
  658.   -- .                                .
  659.   -- .  Delete                        .  BODY
  660.   -- .                                .
  661.   -- ..................................
  662.   function Delete
  663.     ( File_Name      : in STRING )
  664.     return BOOLEAN is
  665.  
  666.   --| Notes (none)
  667.  
  668.     File
  669.       : Text_IO.File_Type;
  670.  
  671.     Result
  672.       : BOOLEAN
  673.         := true;
  674.  
  675.   begin -- Delete
  676.  
  677.     begin
  678.       if Already_Exists(File_Name) then
  679.         Text_IO.Open(File, Text_IO.Out_File, File_Name);
  680.         Text_IO.Delete(File);
  681.       end if;
  682.  
  683.     exception
  684.       when others =>
  685.         Result := false;
  686.     end;
  687.     return Result;
  688.  
  689.   end Delete;
  690.  
  691.   -- ..................................
  692.   -- .                                .
  693.   -- .  Create                        .  BODY
  694.   -- .                                .
  695.   -- ..................................
  696.   procedure Create
  697.     ( Id             : in out File_Type;
  698.       File_Name      : in STRING ) is
  699.  
  700.   --| Notes (none)
  701.  
  702.   begin -- Create
  703.  
  704.     Id             := new FILE_OBJECT;
  705.     Text_IO.Create(Id.File, Text_IO.Out_File, File_Name);
  706.     Id.Is_Open     := true;
  707.     Id.Is_Output_Enabled := true;
  708.  
  709.   exception -- Create -- Create
  710.     when others =>
  711.       raise Cannot_Create_Output_File;
  712.  
  713.   end Create;
  714.  
  715.   -- ..................................
  716.   -- .                                .
  717.   -- .  Put                           .  BODY
  718.   -- .                                .
  719.   -- ..................................
  720.   procedure Put
  721.     ( Id             : in out File_Type;
  722.       Item           : in CHARACTER ) is
  723.  
  724.   --| Notes (none)
  725.  
  726.   begin -- Put
  727.  
  728.     if Id.Is_Open and Id.Is_Output_Enabled then
  729.       Text_IO.Put(Id.File, Item);
  730.     end if;
  731.  
  732.   exception -- Put -- Put
  733.     when others =>
  734.       raise Write_Error;
  735.  
  736.   end Put;
  737.  
  738.   -- ..................................
  739.   -- .                                .
  740.   -- .  Put                           .  BODY
  741.   -- .                                .
  742.   -- ..................................
  743.   procedure Put
  744.     ( Id             : in out File_Type;
  745.       Item           : in STRING ) is
  746.  
  747.   --| Notes (none)
  748.  
  749.   begin -- Put
  750.  
  751.     if Id.Is_Open and Id.Is_Output_Enabled then
  752.       Text_IO.Put(Id.File, Item);
  753.     end if;
  754.  
  755.   exception -- Put -- Put
  756.     when others =>
  757.       raise Write_Error;
  758.  
  759.   end Put;
  760.  
  761.   -- ..................................
  762.   -- .                                .
  763.   -- .  Put_Line                      .  BODY
  764.   -- .                                .
  765.   -- ..................................
  766.   procedure Put_Line
  767.     ( Id             : in out File_Type;
  768.       Item           : in STRING ) is
  769.  
  770.   --| Notes (none)
  771.  
  772.   begin -- Put_Line
  773.  
  774.     if Id.Is_Open and Id.Is_Output_Enabled then
  775.       Text_IO.Put_Line(Id.File, Item);
  776.     end if;
  777.  
  778.   exception -- Put_Line -- Put_Line
  779.     when others =>
  780.       raise Write_Error;
  781.  
  782.   end Put_Line;
  783.  
  784.   -- ..................................
  785.   -- .                                .
  786.   -- .  New_Line                      .  BODY
  787.   -- .                                .
  788.   -- ..................................
  789.   procedure New_Line
  790.     ( Id             : in out File_Type ) is
  791.  
  792.   --| Notes (none)
  793.  
  794.   begin -- New_Line
  795.  
  796.     if Id.Is_Open and Id.Is_Output_Enabled then
  797.       Text_IO.New_Line(Id.File);
  798.     end if;
  799.  
  800.   exception -- New_Line -- New_Line
  801.     when others =>
  802.       raise Write_Error;
  803.  
  804.   end New_Line;
  805.  
  806.   -- ..................................
  807.   -- .                                .
  808.   -- .  New_Page                      .  BODY
  809.   -- .                                .
  810.   -- ..................................
  811.   procedure New_Page
  812.     ( Id             : in out File_Type ) is
  813.  
  814.   --| Notes (none)
  815.  
  816.   begin -- New_Page
  817.  
  818.     if Id.Is_Open and Id.Is_Output_Enabled then
  819.       Text_IO.New_Page(Id.File);
  820.     end if;
  821.  
  822.   exception -- New_Page -- New_Page
  823.     when others =>
  824.       raise Write_Error;
  825.  
  826.   end New_Page;
  827.  
  828.   -- ..................................
  829.   -- .                                .
  830.   -- .  Enable_Output                 .  BODY
  831.   -- .                                .
  832.   -- ..................................
  833.   procedure Enable_Output
  834.     ( Id             : in out File_Type ) is
  835.  
  836.   --| Notes (none)
  837.  
  838.   begin -- Enable_Output
  839.  
  840.     Id.Is_Output_Enabled := true;
  841.  
  842.   end Enable_Output;
  843.  
  844.   -- ..................................
  845.   -- .                                .
  846.   -- .  Disable_Output                .  BODY
  847.   -- .                                .
  848.   -- ..................................
  849.   procedure Disable_Output
  850.     ( Id             : in out File_Type ) is
  851.  
  852.   --| Notes (none)
  853.  
  854.   begin -- Disable_Output
  855.  
  856.     Id.Is_Output_Enabled := false;
  857.  
  858.   end Disable_Output;
  859.  
  860.   -- ..................................
  861.   -- .                                .
  862.   -- .  Close                         .  BODY
  863.   -- .                                .
  864.   -- ..................................
  865.   procedure Close
  866.     ( Id             : in out File_Type ) is
  867.  
  868.   --| Notes (none)
  869.  
  870.   begin -- Close
  871.  
  872.     if Id.Is_Open then
  873.       Text_IO.Close(Id.File);
  874.     end if;
  875.  
  876.   end Close;
  877.  
  878. end FOF_Output_File;
  879. -- **********************************
  880. -- *                                *
  881. -- *  Formatted_Output_File         *  BODY
  882. -- *                                *
  883. -- **********************************
  884. with FOF_Command_Symbols;
  885. with FOF_DYN;
  886. with FOF_Error_Log;
  887. with FOF_Output_File;
  888. package body Formatted_Output_File is
  889.  
  890. --| Notes (none)
  891. --|
  892. --| Modifications
  893. --| 08/16/89   Rick Conn    Initial version
  894. --| 02/26/90   Rick Conn    Remove trailing spaces from @n
  895.  
  896.   subtype HF is
  897.     FOF_DYN.Dyn_String;
  898.  
  899.   type HF_SECTION is
  900.     ( LEFT, CENTER, RIGHT );
  901.  
  902.   type HF_LINES is
  903.     array (Header_Footer_Line, HF_SECTION)
  904.       of HF;
  905.  
  906.   Header_Footer_Default
  907.     : constant HF_LINES
  908.       := (others         => (others         => FOF_DYN.D_String(" ")));
  909.  
  910.   subtype LINE is                                -- very long line for
  911.     STRING (1 .. Maximum_Line_Length * 5);       -- invisible words
  912.  
  913.  
  914.   type FILE_OBJECT is
  915.     record
  916.       Output_Is_Open : BOOLEAN   := false;  -- has file been opened?
  917.       Output_Is_Empty : BOOLEAN;            -- has anything been output?
  918.       Line_Is_Empty  : BOOLEAN;             -- is anything in Current_Line?
  919.       Page_Attr      : Page_Attribute_List; -- left margin, etc.
  920.       Line_Attr      : Line_Attribute_List; -- fill, etc (misnomer)
  921.       Page_Num       : Page_Number;         -- # of current page
  922.       Line_Num       : Line_Number;         -- # of line now being built
  923.       Even_Header    : HF_LINES;            -- for even pages
  924.       Odd_Header     : HF_LINES;            -- for odd pages
  925.       Even_Footer    : HF_LINES;            -- for even pages
  926.       Odd_Footer     : HF_LINES;            -- for odd pages
  927.       Current_Line   : LINE;                -- line being built
  928.       Index          : NATURAL;             -- index of next char to place
  929.                                             --   into Current_Line
  930.       Char_Count     : NATURAL;             -- number of visible chars
  931.                                             --   in Current_Line
  932.       Last_Char      : CHARACTER;           -- last char in Current_Line
  933.       Page_Number_Id : CHARACTER;           -- xlates into page number
  934.                                             --   in headers and footers
  935.       Pn_Format      : Numeric_Format;      -- arabic, lower_ & upper_roman
  936.       Pn_String      : FOF_DYN.Dyn_String;  -- text of page number
  937.       File_Id        : FOF_Output_File.File_Type;
  938.     end record;
  939.  
  940.  
  941.   use FOF_Command_Symbols;
  942.  
  943.   -- ..................................
  944.   -- .                                .
  945.   -- .  Is_Punctuation                .  SPEC & BODY
  946.   -- .                                .
  947.   -- ..................................
  948.   function Is_Punctuation
  949.     ( Item           : in CHARACTER )
  950.       return BOOLEAN is
  951.  
  952.   --| Purpose
  953.   --| Is_Punctuation returns TRUE if Item is one of the characters in
  954.   --| PUNCTUATION_CHARS.
  955.   --|
  956.   --| Exceptions (none)
  957.   --| Notes (none)
  958.  
  959.     Result
  960.       : BOOLEAN
  961.         := false;
  962.  
  963.   begin -- Is_Punctuation
  964.  
  965.     case Item is
  966.       when '.' | ',' | '!' | '?' | ';' =>
  967.         Result         := true;
  968.       when others =>
  969.         Result         := false;
  970.     end case;
  971.     return Result;
  972.  
  973.   end Is_Punctuation;
  974.  
  975.   -- ..................................
  976.   -- .                                .
  977.   -- .  Simple_Break_Page             .  SPEC
  978.   -- .                                .
  979.   -- ..................................
  980.   procedure Simple_Break_Page
  981.     ( Item           : in File );
  982.  
  983.   -- ..................................
  984.   -- .                                .
  985.   -- .  Pnum_As_String                .  SPEC & BODY
  986.   -- .                                .
  987.   -- ..................................
  988.   function Pnum_As_String
  989.     ( Value          : in Page_Number;
  990.       Format         : in Numeric_Format )
  991.       return STRING is
  992.  
  993.   --| Purpose
  994.   --| Pnum_As_String outputs a string (with optional leading blanks)
  995.   --| which contains the input number's representation in ARABIC,
  996.   --| LOWER_ROMAN, or UPPER_ROMAN forms.
  997.   --|
  998.   --| Exceptions (none)
  999.   --|
  1000.   --| Notes
  1001.   --| Value should be less than 1000 if output as a Roman numeral.
  1002.  
  1003.     Result
  1004.       : STRING (1 .. 20)
  1005.         := (others         => ' ');
  1006.  
  1007.     Rover                                        -- Set for leading space
  1008.       : NATURAL
  1009.         := Result'First;
  1010.  
  1011.     Ones
  1012.       : NATURAL
  1013.         := 0;
  1014.  
  1015.     Tens
  1016.       : NATURAL
  1017.         := 0;
  1018.  
  1019.     Hundreds
  1020.       : NATURAL
  1021.         := 0;
  1022.  
  1023.       -- ..................................
  1024.       -- .                                .
  1025.       -- .  Pnum_As_String.Put            .  SPEC & BODY
  1026.       -- .                                .
  1027.       -- ..................................
  1028.  
  1029.     procedure Put
  1030.       ( Item           : in CHARACTER ) is
  1031.  
  1032.     --| Purpose
  1033.     --| Put places a character into the Result buffer, incrementing Rover.
  1034.     --|
  1035.     --| Exceptions (none)
  1036.     --| Notes (none)
  1037.  
  1038.     begin -- Put
  1039.       Rover          := Rover + 1;
  1040.       Result(Rover)  := Item;
  1041.     end Put;
  1042.  
  1043.     -- ..................................
  1044.     -- .                                .
  1045.     -- .  Pnum_As_String.Output         .  SPEC & BODY
  1046.     -- .                                .
  1047.     -- ..................................
  1048.     procedure Output
  1049.       ( Value          : in NATURAL;
  1050.         Lower          : in CHARACTER;
  1051.         Middle         : in CHARACTER;
  1052.         Upper          : in CHARACTER ) is
  1053.  
  1054.     --| Purpose
  1055.     --| Output outputs the appropriate Roman characters representing
  1056.     --| Value into the string Result, incrementing the pointer Rover
  1057.     --| as it goes.  Value must be between 1 and 9, inclusive.
  1058.     --|
  1059.     --| Exceptions (none)
  1060.     --| Notes (none)
  1061.  
  1062.     begin -- Output
  1063.  
  1064.       if Value < 4 then
  1065.         for I in 1 .. Value loop
  1066.           Put(Lower);
  1067.         end loop;
  1068.       elsif Value = 4 then
  1069.         Put(Lower);
  1070.         Put(Middle);
  1071.       elsif (Value >= 5) and (Value < 9) then
  1072.         Put(Middle);
  1073.         if Value > 5 then
  1074.           for I in 1 .. Value - 5 loop
  1075.             Put(Lower);
  1076.           end loop;
  1077.         end if;
  1078.       else
  1079.         Put(Lower);
  1080.         Put(Upper);
  1081.       end if;
  1082.  
  1083.     end Output;
  1084.  
  1085.     -- ..................................
  1086.     -- .                                .
  1087.     -- .  Pnum_As_String.Divide         .  SPEC & BODY
  1088.     -- .                                .
  1089.     -- ..................................
  1090.     procedure Divide
  1091.       ( Value          : in NATURAL ) is
  1092.  
  1093.     --| Purpose
  1094.     --| Divide sets the number of Thousands, Hundreds, Tens, and Ones
  1095.     --| in the passed value for Roman numeral computation.
  1096.     --|
  1097.     --| Exceptions (none)
  1098.     --| Notes (none)
  1099.  
  1100.       Temp
  1101.         : NATURAL
  1102.           := Value;
  1103.  
  1104.     begin -- Divide
  1105.  
  1106.       if Temp >= 100 then
  1107.         Hundreds       := Temp / 100;
  1108.         Temp           := Temp - Hundreds * 100;
  1109.       end if;
  1110.       if Temp >= 10 then
  1111.         Tens           := Temp / 10;
  1112.         Temp           := Temp - Tens * 10;
  1113.       end if;
  1114.       Ones           := Temp;
  1115.  
  1116.     end Divide;
  1117.  
  1118.   begin -- Pnum_As_String
  1119.  
  1120.     case Format is
  1121.  
  1122.       when Arabic =>
  1123.         return Page_Number'Image(Value);
  1124.  
  1125.       when Lower_Roman =>
  1126.         if NATURAL(Value) >= 1000 then
  1127.           Put('z');
  1128.           Put('z');
  1129.           Put('z');
  1130.         else
  1131.           Divide(NATURAL(Value));
  1132.           if Hundreds > 0 then
  1133.             Output(Hundreds, 'c', 'd', 'm');
  1134.           end if;
  1135.           if Tens > 0 then
  1136.             Output(Tens, 'x', 'l', 'c');
  1137.           end if;
  1138.           if Ones > 0 then
  1139.             Output(Ones, 'i', 'v', 'x');
  1140.           end if;
  1141.         end if;
  1142.  
  1143.       when Upper_Roman =>
  1144.         if NATURAL(Value) >= 1000 then
  1145.           Put('Z');
  1146.           Put('Z');
  1147.           Put('Z');
  1148.         else
  1149.           Divide(NATURAL(Value));
  1150.           if Hundreds > 0 then
  1151.             Output(Hundreds, 'C', 'D', 'M');
  1152.           end if;
  1153.           if Tens > 0 then
  1154.             Output(Tens, 'X', 'L', 'C');
  1155.           end if;
  1156.           if Ones > 0 then
  1157.             Output(Ones, 'I', 'V', 'X');
  1158.           end if;
  1159.         end if;
  1160.  
  1161.     end case;
  1162.  
  1163.     return Result(1 .. Rover);
  1164.  
  1165.   exception
  1166.     when others =>
  1167.       FOF_Error_Log.Write_Error(Error_Internal_Pnum);
  1168.       return " ";
  1169.  
  1170.   end Pnum_As_String;
  1171.  
  1172.   -- ..................................
  1173.   -- .                                .
  1174.   -- .  Start_Line                    .  SPEC & BODY
  1175.   -- .                                .
  1176.   -- ..................................
  1177.   procedure Start_Line
  1178.     ( Item           : in File ) is
  1179.  
  1180.   --| Purpose
  1181.   --| This is an internal routine not specified in the package
  1182.   --| specification.  It is used to initialize the Current_Line
  1183.   --| field of the Item object and the associated fields.  It sets
  1184.   --| the left margin.
  1185.   --|
  1186.   --| Exceptions (none)
  1187.   --| Notes (none)
  1188.  
  1189.   begin -- Start_Line
  1190.  
  1191.     if Item.Page_Attr(Temp_Indent) > 0 then
  1192.       Item.Index     := Item.Page_Attr(Temp_Indent)
  1193.           + Item.Page_Attr(Page_Offset);
  1194.       Item.Page_Attr(Temp_Indent) := 0;
  1195.     else
  1196.       Item.Index     := Item.Page_Attr(Left_Margin)
  1197.           + Item.Page_Attr(Left_Indent) + Item.Page_Attr(Page_Offset);
  1198.     end if;
  1199.     if Item.Index < 1 then
  1200.       Item.Index     := 1;
  1201.     end if;
  1202.     Item.Char_Count := Item.Index - 1;
  1203.     Item.Current_Line(1 .. Item.Index) := (others         => ' ');
  1204.     Item.Last_Char := ' ';
  1205.     Item.Line_Is_Empty := false;
  1206.  
  1207.   end Start_Line;
  1208.  
  1209.   -- ..................................
  1210.   -- .                                .
  1211.   -- .  Space_Lines                   .  SPEC & BODY
  1212.   -- .                                .
  1213.   -- ..................................
  1214.   procedure Space_Lines
  1215.     ( Item           : in File ) is
  1216.  
  1217.   --| Purpose
  1218.   --| This is an internal routine not specified in the package
  1219.   --| specification.  It is used to output additional blank lines
  1220.   --| based on the LINE_SPACING setting.
  1221.   --|
  1222.   --| Exceptions (none)
  1223.   --| Notes (none)
  1224.  
  1225.   begin -- Space_Lines
  1226.  
  1227.     if Item.Page_Attr(Line_Spacing) > 0 then
  1228.       if Test_Page(Item, Line_Number(Item.Page_Attr(Line_Spacing))) then
  1229.         for I in 1 .. Item.Page_Attr(Line_Spacing) loop
  1230.           FOF_Output_File.New_Line(Item.File_Id);
  1231.           Item.Line_Num  := Item.Line_Num + 1;
  1232.         end loop;
  1233.       else
  1234.         Simple_Break_Page(Item);
  1235.       end if;
  1236.     end if;
  1237.  
  1238.   end Space_Lines;
  1239.  
  1240.   -- ..................................
  1241.   -- .                                .
  1242.   -- .  Justify_Line                  .  SPEC & BODY
  1243.   -- .                                .
  1244.   -- ..................................
  1245.   procedure Justify_Line
  1246.     ( Item           : in File ) is
  1247.  
  1248.   --| Notes
  1249.   --| This is an internal routine not specified in the package
  1250.   --| specification.  It is used to fill the Current_Line
  1251.   --| with spaces so that the last character is on the right
  1252.   --| margin.
  1253.   --|
  1254.   --| Exceptions (none)
  1255.   --| Notes (none)
  1256.  
  1257.     Spaces_Required
  1258.       : constant NATURAL
  1259.         := Item.Page_Attr(Right_Margin) - Item.Page_Attr(Right_Indent)
  1260.           - Item.Char_Count + Item.Page_Attr(Page_Offset);
  1261.  
  1262.     Spaces_Left
  1263.       : NATURAL
  1264.         := Spaces_Required;
  1265.  
  1266.       -- ..................................
  1267.       -- .                                .
  1268.       -- .  Justify_Line.Justify          .  SPEC & BODY
  1269.       -- .                                .
  1270.       -- ..................................
  1271.  
  1272.     function Justify
  1273.       ( Amount_Left    : in NATURAL )
  1274.         return NATURAL is
  1275.  
  1276.     --| Purpose
  1277.     --| Justify replaces single spaces in Item.Current_Line with
  1278.     --| double spaces until Amount is zero or the end of the
  1279.     --| line is reached.
  1280.     --|
  1281.     --| Exceptions (none)
  1282.     --| Notes (none)
  1283.  
  1284.       type PARSE_STATE is
  1285.         ( BEFORE_TEXT, IN_TEXT, IN_SPACES, DONE );
  1286.  
  1287.       State
  1288.         : PARSE_STATE
  1289.           := BEFORE_TEXT;
  1290.  
  1291.       I                                          -- index for Temp
  1292.         : NATURAL;
  1293.  
  1294.       Amount                                     -- number of spaces to go
  1295.         : NATURAL
  1296.           := Amount_Left;
  1297.  
  1298.       Temp
  1299.         : LINE;
  1300.  
  1301.       Was_In_Spaces
  1302.         : BOOLEAN
  1303.           := false;
  1304.  
  1305.     begin -- Justify
  1306.  
  1307.       I              := 1;
  1308.       for J in 1 .. Item.Index - 1 loop
  1309.         case State is
  1310.           when BEFORE_TEXT =>
  1311.             Temp(I)        := Item.Current_Line(J);
  1312.             I              := I + 1;
  1313.             if Item.Current_Line(J) > ' ' then
  1314.               State          := IN_TEXT;
  1315.             end if;
  1316.           when IN_TEXT =>
  1317.             if Item.Current_Line(J) = ' ' then
  1318.               Temp(I)        := ' ';
  1319.               I              := I + 1;
  1320.               Temp(I)        := ' ';
  1321.               I              := I + 1;
  1322.               Amount         := Amount - 1;
  1323.               Was_In_Spaces  := true;
  1324.               if Amount = 0 then
  1325.                 State          := DONE;
  1326.               else
  1327.                 State          := IN_SPACES;
  1328.               end if;
  1329.             else
  1330.               Temp(I)        := Item.Current_Line(J);
  1331.               I              := I + 1;
  1332.             end if;
  1333.           when IN_SPACES =>
  1334.             Temp(I)        := Item.Current_Line(J);
  1335.             I              := I + 1;
  1336.             if Item.Current_Line(J) /= ' ' then
  1337.               State          := IN_TEXT;
  1338.             end if;
  1339.           when DONE =>
  1340.             Temp(I)        := Item.Current_Line(J);
  1341.             I              := I + 1;
  1342.         end case;
  1343.       end loop;
  1344.  
  1345.       Item.Current_Line := Temp;
  1346.       Item.Index     := I;
  1347.       if not Was_In_Spaces then
  1348.         Amount         := 0;
  1349.       end if;
  1350.       return Amount;
  1351.  
  1352.     end Justify;
  1353.  
  1354.   begin -- Justify_Line
  1355.  
  1356.     while Spaces_Left > 0 loop
  1357.       Spaces_Left    := Justify(Spaces_Left);
  1358.     end loop;
  1359.  
  1360.   end Justify_Line;
  1361.  
  1362.   -- ..................................
  1363.   -- .                                .
  1364.   -- .  Conditional_Break_Page        .  SPEC & BODY
  1365.   -- .                                .
  1366.   -- ..................................
  1367.   procedure Conditional_Break_Page
  1368.     ( Item           : in File ) is
  1369.  
  1370.   --| Purpose
  1371.   --| Checks to see if there are any lines left on the page and
  1372.   --| calls Break_Page if not.
  1373.   --|
  1374.   --| Exceptions (none)
  1375.   --| Notes (none)
  1376.  
  1377.   begin -- Conditional_Break_Page
  1378.  
  1379.     if INTEGER(Item.Line_Num) > Item.Page_Attr(Total_Lines)
  1380.         - (Item.Page_Attr(Bottom_Margin) + Item.Page_Attr(Footer_Lines)) then
  1381.       Simple_Break_Page(Item);
  1382.     end if;
  1383.  
  1384.   end Conditional_Break_Page;
  1385.  
  1386.   -- ..................................
  1387.   -- .                                .
  1388.   -- .  Put_Header_Footer_Line        .  SPEC & BODY
  1389.   -- .                                .
  1390.   -- ..................................
  1391.   procedure Put_Header_Footer_Line
  1392.     ( Item           : in File;
  1393.       Left_Text      : in STRING;
  1394.       Center_Text    : in STRING;
  1395.       Right_Text     : in STRING;
  1396.       Page_Num       : in STRING ) is
  1397.  
  1398.   --| Purpose
  1399.   --| This is an internal routine not specified in the package
  1400.   --| specification.  It outputs a header or a footer line, placing
  1401.   --| the Page_Num string (which MUST be created by Current_Page) into
  1402.   --| it wherever the Item.Page_Number_Id character is found.  The
  1403.   --| Left_Text string is left-justified against the left margin
  1404.   --| (first character starts on the left margin), the Center_Text
  1405.   --| string is centered between the left and right margins, and
  1406.   --| the Right_Text string is right-justified against the right
  1407.   --| margin (the last character falls on the right margin).
  1408.   --|
  1409.   --| Exceptions (none)
  1410.   --| Notes (none)
  1411.  
  1412.     Hf_Line
  1413.       : LINE
  1414.         := (others         => ' ');
  1415.  
  1416.     Hf_Last
  1417.       : NATURAL
  1418.         := Item.Page_Attr(Right_Margin) + Item.Page_Attr(Page_Offset);
  1419.  
  1420.     Hf_Last_Save
  1421.       : NATURAL;
  1422.  
  1423.     Left_Text_Lower
  1424.       : constant NATURAL
  1425.         := Item.Page_Attr(Left_Margin) + Item.Page_Attr(Page_Offset);
  1426.  
  1427.     Left_Text_Upper
  1428.       : NATURAL;
  1429.  
  1430.     Right_Text_Lower
  1431.       : NATURAL;
  1432.  
  1433.     Right_Text_Upper
  1434.       : constant NATURAL
  1435.         := Item.Page_Attr(Right_Margin) + Item.Page_Attr(Page_Offset);
  1436.  
  1437.     Center_Point
  1438.       : constant NATURAL
  1439.         := (Right_Text_Upper - Left_Text_Lower) / 2 + Left_Text_Lower;
  1440.  
  1441.     Center_Text_Lower
  1442.       : NATURAL;
  1443.  
  1444.     Center_Text_Upper
  1445.       : NATURAL;
  1446.  
  1447.     Temp_String
  1448.       : LINE;
  1449.  
  1450.     Temp_Length
  1451.       : NATURAL;
  1452.  
  1453.       -- ..............................................
  1454.       -- .                                            .
  1455.       -- .  Put_Header_Footer_Line.Build_Temp_String  .  SPEC & BODY
  1456.       -- .                                            .
  1457.       -- ..............................................
  1458.  
  1459.     procedure Build_Temp_String
  1460.       ( Str            : in STRING ) is
  1461.  
  1462.     --| Purpose
  1463.     --| Build_Temp_String analyzes the input string for the Page_Number_Id
  1464.     --| character, building a new output string in the global Temp_String
  1465.     --| vector which contains the input string with the literal page
  1466.     --| number substituted for the Page_Number_Id character.
  1467.     --|
  1468.     --| Exceptions (none)
  1469.     --| Notes (none)
  1470.  
  1471.       J
  1472.         : NATURAL
  1473.           := 1;
  1474.  
  1475.     begin -- Build_Temp_String
  1476.  
  1477.       for I in Str'First .. Str'Last loop
  1478.         if Str(I) = Item.Page_Number_Id then
  1479.           for K in Page_Num'Range loop
  1480.             Temp_String(J) := Page_Num(K);
  1481.             J              := J + 1;
  1482.           end loop;
  1483.         else
  1484.           Temp_String(J) := Str(I);
  1485.           J              := J + 1;
  1486.         end if;
  1487.       end loop;
  1488.       Temp_Length    := J - 1;
  1489.       J := 0;
  1490.       -- remove trailing spaces
  1491.       for I in reverse 1 .. Temp_Length loop
  1492.         if Temp_String(I) > ' ' then
  1493.           J := I;
  1494.           exit;
  1495.         end if;
  1496.       end loop;
  1497.       Temp_Length := J;
  1498.  
  1499.       Left_Text_Upper := Item.Page_Attr(Left_Margin) + Temp_Length - 1
  1500.           + Item.Page_Attr(Page_Offset);
  1501.  
  1502.       Right_Text_Lower := Item.Page_Attr(Right_Margin) - Temp_Length + 1
  1503.           + Item.Page_Attr(Page_Offset);
  1504.  
  1505.       Center_Text_Lower := Center_Point - Temp_Length / 2;
  1506.  
  1507.       Center_Text_Upper := Center_Text_Lower + Temp_Length - 1;
  1508.  
  1509.     end Build_Temp_String;
  1510.  
  1511.   begin -- Put_Header_Footer_Line
  1512.  
  1513.     if Left_Text'Length > 0 then
  1514.       Build_Temp_String(Left_Text);
  1515.       if Temp_Length < Right_Text_Upper - Left_Text_Lower + 1 then
  1516.         Hf_Line(Left_Text_Lower .. Left_Text_Upper) := Temp_String(1 ..
  1517.             Temp_Length);
  1518.       else
  1519.         Hf_Line(Left_Text_Lower .. Right_Text_Upper) := Temp_String(1 ..
  1520.             (Right_Text_Upper - Left_Text_Lower + 1));
  1521.       end if;
  1522.     end if;
  1523.     if Right_Text'Length > 0 then
  1524.       Build_Temp_String(Right_Text);
  1525.       if Temp_Length < Right_Text_Upper - Left_Text_Lower + 1 then
  1526.         Hf_Line(Right_Text_Lower .. Right_Text_Upper) := Temp_String(1 ..
  1527.             Temp_Length);
  1528.       else
  1529.         Hf_Line(Left_Text_Lower .. Right_Text_Upper) := Temp_String(1 ..
  1530.             (Right_Text_Upper - Left_Text_Lower + 1));
  1531.       end if;
  1532.     end if;
  1533.     if Center_Text'Length > 0 then
  1534.       Build_Temp_String(Center_Text);
  1535.       if Temp_Length < Right_Text_Upper - Left_Text_Lower + 1 then
  1536.         Hf_Line(Center_Text_Lower .. Center_Text_Upper) := Temp_String(1 ..
  1537.             Temp_Length);
  1538.       else
  1539.         Hf_Line(Left_Text_Lower .. Right_Text_Upper) := Temp_String(1 ..
  1540.             (Right_Text_Upper - Left_Text_Lower + 1));
  1541.       end if;
  1542.     end if;
  1543.     Hf_Last_Save   := Hf_Last;
  1544.     Hf_Last        := 1;
  1545.     for I in reverse 1 .. Hf_Last_Save loop
  1546.       if Hf_Line(I) /= ' ' then
  1547.         Hf_Last        := I;
  1548.         exit;
  1549.       end if;
  1550.     end loop;
  1551.     FOF_Output_File.Put_Line(Item.File_Id, Hf_Line(1 .. Hf_Last));
  1552.     Item.Line_Num  := Item.Line_Num + 1;
  1553.  
  1554.   exception
  1555.     when others =>
  1556.       FOF_Error_Log.Write_Error(Error_Internal_Hf_Line);
  1557.  
  1558.   end Put_Header_Footer_Line;
  1559.  
  1560.   -- ..................................
  1561.   -- .                                .
  1562.   -- .  Output_Top_Of_Page            .  SPEC & BODY
  1563.   -- .                                .
  1564.   -- ..................................
  1565.   procedure Output_Top_Of_Page
  1566.     ( Item           : in File ) is
  1567.  
  1568.   --| Purpose
  1569.   --| This is an internal routine not specified in the package
  1570.   --| specification.  Assuming that the output is at the top
  1571.   --| of page, it increments the Item.Page_Num, outputs
  1572.   --| the appropriate number of blank lines as per the Top_Margin,
  1573.   --| and outputs the header lines (distinguishing between even and
  1574.   --| odd pages).
  1575.   --|
  1576.   --| Exceptions (none)
  1577.   --| Notes (none)
  1578.  
  1579.     Is_Even
  1580.       : BOOLEAN;
  1581.  
  1582.   begin -- Output_Top_Of_Page
  1583.  
  1584.     Item.Line_Num  := 1;
  1585.     if Item.Page_Attr(Top_Margin) > 0 then
  1586.       for I in 1 .. Item.Page_Attr(Top_Margin) loop
  1587.         FOF_Output_File.New_Line(Item.File_Id);
  1588.         Item.Line_Num  := Item.Line_Num + 1;
  1589.       end loop;
  1590.     end if;
  1591.     if Item.Page_Attr(Header_Lines) > 0 then
  1592.       if Item.Page_Num / 2 * 2 = Item.Page_Num then
  1593.         Is_Even        := true;
  1594.       else
  1595.         Is_Even        := false;
  1596.       end if;
  1597.       for I in 1 .. Header_Footer_Line(Item.Page_Attr(Header_Lines)) loop
  1598.         if Is_Even then
  1599.           Put_Header_Footer_Line(Item, FOF_DYN.Str(Item.Even_Header(I, LEFT)),
  1600.               FOF_DYN.Str(Item.Even_Header(I, CENTER)),
  1601.               FOF_DYN.Str(Item.Even_Header(I, RIGHT)),
  1602.               Current_Page(Item));
  1603.         else
  1604.           Put_Header_Footer_Line(Item, FOF_DYN.Str(Item.Odd_Header(I, LEFT)),
  1605.               FOF_DYN.Str(Item.Odd_Header(I, CENTER)),
  1606.               FOF_DYN.Str(Item.Odd_Header(I, RIGHT)),
  1607.               Current_Page(Item));
  1608.         end if;
  1609.       end loop;
  1610.     end if;
  1611.  
  1612.   exception
  1613.     when others =>
  1614.       FOF_Error_Log.Write_Error(Error_Internal_Top);
  1615.  
  1616.   end Output_Top_Of_Page;
  1617.  
  1618.   -- ..................................
  1619.   -- .                                .
  1620.   -- .  Output_Bottom_Of_Page         .  BODY
  1621.   -- .                                .
  1622.   -- ..................................
  1623.   procedure Output_Bottom_Of_Page
  1624.     ( Item           : in File ) is
  1625.  
  1626.   --| Purpose
  1627.   --| Output_Bottom_Of_Page determines how many blank lines are left
  1628.   --| in the text area (between the top margin/header combination and
  1629.   --| the bottom margin/footer combination) and outputs blank lines in
  1630.   --| order to reach the first footer line.  It then outputs the
  1631.   --| footer (distinguishing between even and odd page footers) and
  1632.   --| advances over the bottom margin (with either blank lines or
  1633.   --| form feeds).
  1634.   --|
  1635.   --| Exceptions (none)
  1636.   --| Notes (none)
  1637.  
  1638.     Lines_Left
  1639.       : Line_Number;
  1640.  
  1641.     Is_Even
  1642.       : BOOLEAN;
  1643.  
  1644.   begin -- Output_Bottom_Of_Page
  1645.  
  1646.     Lines_Left     := Line_Number(Item.Page_Attr(Total_Lines)
  1647.         - (Item.Page_Attr(Bottom_Margin) + Item.Page_Attr(Footer_Lines)))
  1648.         - Item.Line_Num + 1;
  1649.     if Lines_Left < 0 then
  1650.       Lines_Left     := 0;
  1651.     end if;
  1652.     if Lines_Left > 0 then
  1653.       for I in 1 .. Lines_Left loop
  1654.         FOF_Output_File.New_Line(Item.File_Id);
  1655.         Item.Line_Num  := Item.Line_Num + 1;
  1656.       end loop;
  1657.     end if;
  1658.     if Item.Page_Attr(Footer_Lines) > 0 then
  1659.       if Item.Page_Num / 2 * 2 = Item.Page_Num then
  1660.         Is_Even        := true;
  1661.       else
  1662.         Is_Even        := false;
  1663.       end if;
  1664.       for I in 1 .. Header_Footer_Line(Item.Page_Attr(Footer_Lines)) loop
  1665.         if Is_Even then
  1666.           Put_Header_Footer_Line(Item, FOF_DYN.Str(Item.Even_Footer(I, LEFT)),
  1667.               FOF_DYN.Str(Item.Even_Footer(I, CENTER)),
  1668.               FOF_DYN.Str(Item.Even_Footer(I, RIGHT)),
  1669.               Current_Page(Item));
  1670.         else
  1671.           Put_Header_Footer_Line(Item, FOF_DYN.Str(Item.Odd_Footer(I, LEFT)),
  1672.               FOF_DYN.Str(Item.Odd_Footer(I, CENTER)),
  1673.               FOF_DYN.Str(Item.Odd_Footer(I, RIGHT)),
  1674.               Current_Page(Item));
  1675.         end if;
  1676.       end loop;
  1677.     end if;
  1678.     if Item.Page_Attr(Bottom_Margin) > 0 then
  1679.       if Item.Line_Attr(Use_Form_Feed) = On then
  1680.         FOF_Output_File.New_Page(Item.File_Id);
  1681.       else
  1682.         for I in 1 .. Item.Page_Attr(Bottom_Margin) loop
  1683.           FOF_Output_File.New_Line(Item.File_Id);
  1684.           Item.Line_Num  := Item.Line_Num + 1;
  1685.         end loop;
  1686.       end if;
  1687.     end if;
  1688.  
  1689.   exception
  1690.     when others =>
  1691.       FOF_Error_Log.Write_Error(Error_Internal_Bottom);
  1692.  
  1693.   end Output_Bottom_Of_Page;
  1694.  
  1695.   -- ..................................
  1696.   -- .                                .
  1697.   -- .  Simple_Break_Page             .  BODY
  1698.   -- .                                .
  1699.   -- ..................................
  1700.   procedure Simple_Break_Page
  1701.     ( Item           : in File ) is
  1702.  
  1703.   --| Purpose
  1704.   --| Simple_Break_Page outputs to the bottom of the page and the
  1705.   --| top of the next page if paging is on.
  1706.   --|
  1707.   --| Exceptions (none)
  1708.   --| Notes (none)
  1709.  
  1710.   begin -- Simple_Break_Page
  1711.  
  1712.     if Item.Line_Attr(Paging) = On then
  1713.       Output_Bottom_Of_Page(Item);
  1714.       Item.Page_Num  := Item.Page_Num + 1;
  1715.       Output_Top_Of_Page(Item);
  1716.     else
  1717.       Item.Line_Num  := 1;
  1718.     end if;
  1719.  
  1720.   end Simple_Break_Page;
  1721.  
  1722.   -- ..................................
  1723.   -- .                                .
  1724.   -- .  Simple_Break_Page             .  SPEC & BODY
  1725.   -- .                                .
  1726.   -- ..................................
  1727.   procedure Simple_Break_Page
  1728.     ( Item           : in File;
  1729.       New_Page_Num   : in Page_Number ) is
  1730.  
  1731.   --| Purpose
  1732.   --| Simple_Break_Page outputs to the bottom of the page and the
  1733.   --| top of the next page if paging is on.  It sets the number of
  1734.   --| the new page to New_Page_Num.
  1735.   --|
  1736.   --| Exceptions (none)
  1737.   --| Notes (none)
  1738.  
  1739.   begin -- Simple_Break_Page
  1740.  
  1741.     if Item.Line_Attr(Paging) = On then
  1742.       Output_Bottom_Of_Page(Item);
  1743.       Item.Page_Num  := New_Page_Num;
  1744.       Output_Top_Of_Page(Item);
  1745.     else
  1746.       Item.Page_Num  := New_Page_Num;
  1747.       Item.Line_Num  := 1;
  1748.     end if;
  1749.  
  1750.   end Simple_Break_Page;
  1751.  
  1752.   -- ..................................
  1753.   -- .                                .
  1754.   -- .  Open                          .  BODY
  1755.   -- .                                .
  1756.   -- ..................................
  1757.  
  1758.   procedure Open
  1759.     ( Item           : in out File;
  1760.       File_Name      : in STRING;
  1761.       Result         : out Status ) is
  1762.  
  1763.   --| Notes
  1764.   --| Open the output file object and set
  1765.   --| defaults.  Map the FOF_Output_File.Open status to the
  1766.   --| Formatted_Output_File.Open status.
  1767.  
  1768.     Local_Result
  1769.       : Status;
  1770.  
  1771.   begin -- Open
  1772.  
  1773.     Item           := new FILE_OBJECT;
  1774.     begin
  1775.       FOF_Output_File.Create(Item.File_Id, File_Name);
  1776.       Local_Result   := Ok;
  1777.     exception
  1778.       when others =>
  1779.         Local_Result   := Not_Ok;
  1780.     end;
  1781.     if Local_Result = Ok then
  1782.       Item.Output_Is_Open := true;
  1783.       Item.Output_Is_Empty := true;
  1784.       Item.Line_Is_Empty := true;
  1785.       Item.Page_Attr := Page_Attribute_Defaults;
  1786.       Item.Line_Attr := Line_Attribute_Defaults;
  1787.       Item.Page_Num  := 0;
  1788.       Item.Line_Num  := 1;
  1789.       Item.Even_Header := Header_Footer_Default;
  1790.       Item.Odd_Header := Header_Footer_Default;
  1791.       Item.Even_Footer := Header_Footer_Default;
  1792.       Item.Odd_Footer := Header_Footer_Default;
  1793.       Item.Page_Number_Id := Page_Number_Id_Default;
  1794.       Item.Pn_Format := Arabic;
  1795.       Item.Pn_String := FOF_DYN.D_String(Page_Number_Id_Default);
  1796.     else
  1797.       Item.Output_Is_Open := false;
  1798.     end if;
  1799.     Result         := Local_Result;
  1800.  
  1801.   end Open;
  1802.  
  1803.   -- ..................................
  1804.   -- .                                .
  1805.   -- .  Close                         .  BODY
  1806.   -- .                                .
  1807.   -- ..................................
  1808.   procedure Close
  1809.     ( Item           : in File ) is
  1810.  
  1811.   --| Notes (none)
  1812.  
  1813.   begin -- Close
  1814.  
  1815.     if not Item.Output_Is_Open then
  1816.       raise File_Not_Open;
  1817.     end if;
  1818.     if Item.Line_Attr(Paging) = On then
  1819.       Break_Line(Item);
  1820.       Output_Bottom_Of_Page(Item);
  1821.     else
  1822.       Item.Line_Num  := 1;
  1823.     end if;
  1824.     FOF_Output_File.Close(Item.File_Id);
  1825.     Item.Output_Is_Open := false;
  1826.  
  1827.   end Close;
  1828.  
  1829.   -- ..................................
  1830.   -- .                                .
  1831.   -- .  Put_Invisible_Word            .  BODY
  1832.   -- .                                .
  1833.   -- ..................................
  1834.   procedure Put_Invisible_Word
  1835.     ( Item           : in File;
  1836.       What           : in STRING ) is
  1837.  
  1838.   --| Notes (none)
  1839.  
  1840.   begin -- Put_Invisible_Word
  1841.     if not Item.Output_Is_Open then
  1842.       raise File_Not_Open;
  1843.     end if;
  1844.     if Item.Output_Is_Empty then
  1845.       if Item.Line_Attr(Paging) = On then
  1846.         Item.Page_Num  := Item.Page_Num + 1;
  1847.         Output_Top_Of_Page(Item);
  1848.       else
  1849.         Item.Line_Num  := 1;
  1850.       end if;
  1851.       Item.Output_Is_Empty := false;
  1852.     end if;
  1853.     if Item.Line_Is_Empty then
  1854.       Start_Line(Item);
  1855.     end if;
  1856.     Item.Current_Line(Item.Index .. Item.Index + What'Length - 1) := What;
  1857.     Item.Index     := Item.Index + What'Length;
  1858.  
  1859.   exception
  1860.     when others =>
  1861.       FOF_Error_Log.Write_Error(Error_Internal_Put_Invisible);
  1862.  
  1863.   end Put_Invisible_Word;
  1864.  
  1865.   -- ..................................
  1866.   -- .                                .
  1867.   -- .  Put_Word                      .  BODY
  1868.   -- .                                .
  1869.   -- ..................................
  1870.   procedure Put_Word
  1871.     ( Item           : in File;
  1872.       What           : in STRING ) is
  1873.  
  1874.   --| Notes (none)
  1875.  
  1876.     Adjustment_Length
  1877.       : NATURAL;
  1878.  
  1879.     Adjustment_String
  1880.       : constant STRING                          -- 2 spaces
  1881.         := "  ";
  1882.  
  1883.       -- ..................................
  1884.       -- .                                .
  1885.       -- .  Put_Word.Put_What             .  SPEC & BODY
  1886.       -- .                                .
  1887.       -- ..................................
  1888.  
  1889.     procedure Put_What is
  1890.  
  1891.     --| Notes
  1892.     --| Put_What is used to place the What string into Item.Current_Line
  1893.     --| and update the other variables as necessary.
  1894.  
  1895.       Full_Adjustment_Length
  1896.         : NATURAL
  1897.           := Adjustment_Length + What'Length;
  1898.  
  1899.       Full_String_Length
  1900.         : NATURAL
  1901.           := Item.Char_Count + Full_Adjustment_Length;
  1902.  
  1903.       Lower_Index
  1904.         : NATURAL
  1905.           := Item.Index;
  1906.  
  1907.       Upper_Index
  1908.         : NATURAL
  1909.           := Item.Index + Full_Adjustment_Length - 1;
  1910.  
  1911.     begin -- Put_What
  1912.  
  1913.       Item.Current_Line(Lower_Index .. Upper_Index) := Adjustment_String(1 ..
  1914.           Adjustment_Length) & What;
  1915.       Item.Index     := Upper_Index + 1;
  1916.       Item.Char_Count := Full_String_Length;
  1917.       Item.Last_Char := Item.Current_Line(Item.Index - 1);
  1918.       if Item.Line_Attr(Underline) = On then
  1919.         for I in 1 .. What'Length loop
  1920.           Item.Current_Line(Item.Index) := Ascii.Bs;
  1921.           Item.Index     := Item.Index + 1;
  1922.         end loop;
  1923.         for I in What'range loop
  1924.           if Item.Line_Attr(Underline_Punct) = Off then
  1925.             if Is_Punctuation(What(I)) then
  1926.               Item.Current_Line(Item.Index) := What(I);
  1927.             else
  1928.               Item.Current_Line(Item.Index) := '_';
  1929.             end if;
  1930.           else
  1931.             Item.Current_Line(Item.Index) := '_';
  1932.           end if;
  1933.           Item.Index     := Item.Index + 1;
  1934.         end loop;
  1935.       end if;
  1936.       if Item.Line_Attr(Bold) = On then
  1937.         for I in 1 .. What'Length loop
  1938.           Item.Current_Line(Item.Index) := Ascii.Bs;
  1939.           Item.Index     := Item.Index + 1;
  1940.         end loop;
  1941.         for I in What'range loop
  1942.           Item.Current_Line(Item.Index) := What(I);
  1943.           Item.Index     := Item.Index + 1;
  1944.         end loop;
  1945.       end if;
  1946.  
  1947.     exception
  1948.       when others =>
  1949.         FOF_Error_Log.Write_Error(Error_Internal_Put_What);
  1950.  
  1951.     end Put_What;
  1952.  
  1953.   begin -- Put_Word
  1954.  
  1955.     if not Item.Output_Is_Open then
  1956.       raise File_Not_Open;
  1957.     end if;
  1958.  
  1959.     if Item.Output_Is_Empty then
  1960.       if Item.Line_Attr(Paging) = On then
  1961.         Item.Page_Num  := Item.Page_Num + 1;
  1962.         Output_Top_Of_Page(Item);
  1963.       else
  1964.         Item.Line_Num  := 1;
  1965.       end if;
  1966.       Item.Output_Is_Empty := false;
  1967.     end if;
  1968.  
  1969.     if Item.Line_Is_Empty then
  1970.       Adjustment_Length := 0;
  1971.     else
  1972.       case Item.Last_Char is
  1973.         when ' ' =>
  1974.           Adjustment_Length := 0;
  1975.         when '.' =>
  1976.           Adjustment_Length := 2;
  1977.         when others =>
  1978.           Adjustment_Length := 1;
  1979.       end case;
  1980.     end if;
  1981.  
  1982.     if Item.Line_Attr(Fill) = On then
  1983.  
  1984.       if Item.Char_Count + Adjustment_Length + What'Length
  1985.           <= Item.Page_Attr(Right_Margin) - Item.Page_Attr(Right_Indent)
  1986.           + Item.Page_Attr(Page_Offset) then
  1987.  
  1988.         -- FILL is on and there is enough room on the line
  1989.         if Item.Line_Is_Empty then
  1990.           Start_Line(Item);
  1991.         end if;
  1992.         Put_What;
  1993.  
  1994.       else
  1995.  
  1996.         -- FILL is on, but not enough room on line
  1997.         if Item.Line_Attr(Justify) = On and not Item.Line_Is_Empty then
  1998.           Justify_Line(Item);
  1999.         end if;
  2000.         Break_Line(Item);
  2001.  
  2002.         Start_Line(Item);
  2003.         Adjustment_Length := 0;
  2004.         Put_What;
  2005.  
  2006.       end if;
  2007.  
  2008.     else
  2009.  
  2010.     -- No FILL, so no JUSTIFY either
  2011.       if Item.Line_Is_Empty then
  2012.         Start_Line(Item);
  2013.       end if;
  2014.       Put_What;
  2015.  
  2016.     end if;
  2017.  
  2018.   exception
  2019.     when others =>
  2020.       FOF_Error_Log.Write_Error(Error_Internal_Put_Word);
  2021.  
  2022.   end Put_Word;
  2023.  
  2024.   -- ..................................
  2025.   -- .                                .
  2026.   -- .  Put_Line                      .  BODY
  2027.   -- .                                .
  2028.   -- ..................................
  2029.   procedure Put_Line
  2030.     ( Item           : in File;
  2031.       What           : in STRING ) is
  2032.  
  2033.   --| Notes (none)
  2034.  
  2035.     First
  2036.       : NATURAL;
  2037.  
  2038.     Last
  2039.       : NATURAL;
  2040.  
  2041.     Temp
  2042.       : NATURAL;
  2043.  
  2044.     type PARSE_STATE is
  2045.       ( IN_WHITE_SPACE, IN_TEXT );
  2046.  
  2047.     Current_State
  2048.       : PARSE_STATE;
  2049.  
  2050.   begin -- Put_Line
  2051.  
  2052.     if not Item.Output_Is_Open then
  2053.       raise File_Not_Open;
  2054.     end if;
  2055.  
  2056.     if Item.Output_Is_Empty then
  2057.       if Item.Line_Attr(Paging) = On then
  2058.         Item.Page_Num  := Item.Page_Num + 1;
  2059.         Output_Top_Of_Page(Item);
  2060.       else
  2061.         Item.Line_Num  := 1;
  2062.       end if;
  2063.       Item.Output_Is_Empty := false;
  2064.     end if;
  2065.  
  2066.     if Item.Line_Attr(Fill) = Off then
  2067.  
  2068.     -- No FILL, so break previous line and output as a line
  2069.       Break_Line(Item);
  2070.       Conditional_Break_Page(Item);
  2071.       Start_Line(Item);                          -- for margin settings
  2072.       Item.Line_Is_Empty := true;
  2073.       if Item.Line_Attr(CENTER) = On then
  2074.         Temp           := (Item.Page_Attr(Right_Margin)
  2075.             - Item.Page_Attr(Right_Indent)) - (Item.Page_Attr(Left_Margin)
  2076.             + Item.Page_Attr(Left_Indent)) + 1;
  2077.         if Temp > What'Length then
  2078.           Temp           := (Temp - What'Length) / 2;
  2079.           for I in 1 .. Temp loop
  2080.             FOF_Output_File.Put(Item.File_Id, ' ');
  2081.           end loop;
  2082.         end if;
  2083.       end if;
  2084.       FOF_Output_File.Put(Item.File_Id,
  2085.           Item.Current_Line(1 .. Item.Char_Count) & What);
  2086.       if Item.Line_Attr(Bold) = On then
  2087.         for I in 1 .. What'Length loop
  2088.           FOF_Output_File.Put(Item.File_Id, Ascii.Bs);
  2089.         end loop;
  2090.         for I in What'range loop
  2091.           FOF_Output_File.Put(Item.File_Id, What(I));
  2092.         end loop;
  2093.       end if;
  2094.       if Item.Line_Attr(Underline) = On then
  2095.         for I in 1 .. What'Length loop
  2096.           FOF_Output_File.Put(Item.File_Id, Ascii.Bs);
  2097.         end loop;
  2098.         for I in What'range loop
  2099.           if What(I) > ' ' then
  2100.             if Item.Line_Attr(Underline_Punct) = Off then
  2101.               if Is_Punctuation(What(I)) then
  2102.                 FOF_Output_File.Put(Item.File_Id, What(I));
  2103.               else
  2104.                 FOF_Output_File.Put(Item.File_Id, '_');
  2105.               end if;
  2106.             else
  2107.               FOF_Output_File.Put(Item.File_Id, '_');
  2108.             end if;
  2109.           else
  2110.             FOF_Output_File.Put(Item.File_Id, What(I));
  2111.           end if;
  2112.         end loop;
  2113.       end if;
  2114.       FOF_Output_File.New_Line(Item.File_Id);
  2115.       Item.Line_Num  := Item.Line_Num + 1;
  2116.       Space_Lines(Item);
  2117.  
  2118.     else
  2119.  
  2120.     -- FILL, so parse out each word and use Put_Word to output
  2121.       Current_State  := IN_WHITE_SPACE;
  2122.       for I in What'First .. What'Last loop
  2123.         case Current_State is
  2124.           when IN_WHITE_SPACE =>
  2125.             if What(I) > ' ' then
  2126.               First          := I;
  2127.               Current_State  := IN_TEXT;
  2128.             end if;
  2129.           when IN_TEXT =>
  2130.             if What(I) <= ' ' then
  2131.               Last           := I - 1;
  2132.               Put_Word(Item, What(First .. Last));
  2133.               Current_State  := IN_WHITE_SPACE;
  2134.             end if;
  2135.         end case;
  2136.       end loop;
  2137.       if Current_State = IN_TEXT then
  2138.         Last           := What'Last;
  2139.         Put_Word(Item, What(First .. Last));
  2140.       end if;
  2141.  
  2142.     end if;
  2143.  
  2144.   exception
  2145.     when others =>
  2146.       FOF_Error_Log.Write_Error(Error_Internal_Put_Line);
  2147.  
  2148.   end Put_Line;
  2149.  
  2150.   -- ..................................
  2151.   -- .                                .
  2152.   -- .  Break_Line                    .  BODY
  2153.   -- .                                .
  2154.   -- ..................................
  2155.   procedure Break_Line
  2156.     ( Item           : in File ) is
  2157.  
  2158.   --| Notes
  2159.   --| Break_Line checks to see if the Current_Line is empty, and,
  2160.   --| if not, outputs it and sets the empty flag to TRUE.  Page
  2161.   --| breaks are also handled if necessary.
  2162.  
  2163.   begin -- Break_Line
  2164.  
  2165.     if not Item.Output_Is_Open then
  2166.       raise File_Not_Open;
  2167.     end if;
  2168.     if not Item.Line_Is_Empty then
  2169.       Conditional_Break_Page(Item);
  2170.       FOF_Output_File.Put_Line(Item.File_Id,
  2171.           Item.Current_Line(1 .. Item.Index - 1));
  2172.       Item.Line_Num  := Item.Line_Num + 1;
  2173.       Space_Lines(Item);
  2174.       Item.Line_Is_Empty := true;
  2175.     end if;
  2176.  
  2177.   exception
  2178.     when others =>
  2179.       FOF_Error_Log.Write_Error(Error_Internal_Break_Line);
  2180.  
  2181.   end Break_Line;
  2182.  
  2183.   -- ..................................
  2184.   -- .                                .
  2185.   -- .  Current_Line                  .  BODY
  2186.   -- .                                .
  2187.   -- ..................................
  2188.   function Current_Line
  2189.     ( Item           : in File )
  2190.       return Line_Number is
  2191.  
  2192.   --| Notes (none)
  2193.  
  2194.   begin -- Current_Line
  2195.  
  2196.     if not Item.Output_Is_Open then
  2197.       raise File_Not_Open;
  2198.     end if;
  2199.     return Item.Line_Num;
  2200.  
  2201.   end Current_Line;
  2202.  
  2203.   -- ..................................
  2204.   -- .                                .
  2205.   -- .  Skip                          .  BODY
  2206.   -- .                                .
  2207.   -- ..................................
  2208.   procedure Skip
  2209.     ( Item           : in File;
  2210.       Number_Of_Lines : in Line_Number := 1 ) is
  2211.  
  2212.   --| Notes (none)
  2213.  
  2214.   begin -- Skip
  2215.  
  2216.     if not Item.Output_Is_Open then
  2217.       raise File_Not_Open;
  2218.     end if;
  2219.     if Item.Output_Is_Empty then
  2220.       if Item.Line_Attr(Paging) = On then
  2221.         Item.Page_Num  := Item.Page_Num + 1;
  2222.         Output_Top_Of_Page(Item);
  2223.       else
  2224.         Item.Line_Num  := 1;
  2225.       end if;
  2226.       Item.Output_Is_Empty := false;
  2227.     end if;
  2228.     Break_Line(Item);
  2229.     if Test_Page(Item, Number_Of_Lines + Number_Of_Lines
  2230.         * Line_Number(Item.Page_Attr(Line_Spacing))) then
  2231.       for I in 1 .. Number_Of_Lines loop
  2232.         FOF_Output_File.New_Line(Item.File_Id);
  2233.         Item.Line_Num  := Item.Line_Num + 1;
  2234.         Space_Lines(Item);
  2235.       end loop;
  2236.     else
  2237.       Simple_Break_Page(Item);
  2238.     end if;
  2239.  
  2240.   exception
  2241.     when others =>
  2242.       FOF_Error_Log.Write_Error(Error_Internal_Skip);
  2243.  
  2244.   end Skip;
  2245.  
  2246.   -- ..................................
  2247.   -- .                                .
  2248.   -- .  Break_Page                    .  BODY
  2249.   -- .                                .
  2250.   -- ..................................
  2251.   procedure Break_Page
  2252.     ( Item           : in File ) is
  2253.  
  2254.   --| Notes
  2255.   --| Issues blank lines for the rest of the text area, outputs footer
  2256.   --| and bottom margin, and outputs header for next page.
  2257.  
  2258.   begin -- Break_Page
  2259.  
  2260.     if not Item.Output_Is_Open then
  2261.       raise File_Not_Open;
  2262.     end if;
  2263.     Break_Line(Item);
  2264.     Simple_Break_Page(Item);
  2265.  
  2266.   exception
  2267.     when others =>
  2268.       FOF_Error_Log.Write_Error(Error_Internal_Break_Page_1);
  2269.  
  2270.   end Break_Page;
  2271.  
  2272.   -- ..................................
  2273.   -- .                                .
  2274.   -- .  Break_Page                    .  BODY
  2275.   -- .                                .
  2276.   -- ..................................
  2277.   procedure Break_Page
  2278.     ( Item           : in File;
  2279.       New_Page_Num   : in Page_Number ) is
  2280.  
  2281.   --| Notes (none)
  2282.  
  2283.   begin -- Break_Page
  2284.  
  2285.     if not Item.Output_Is_Open then
  2286.       raise File_Not_Open;
  2287.     end if;
  2288.     Break_Line(Item);
  2289.     Simple_Break_Page(Item, New_Page_Num);
  2290.  
  2291.   exception
  2292.     when others =>
  2293.       FOF_Error_Log.Write_Error(Error_Internal_Break_Page_2);
  2294.  
  2295.   end Break_Page;
  2296.  
  2297.   -- ..................................
  2298.   -- .                                .
  2299.   -- .  Current_Page                  .  BODY
  2300.   -- .                                .
  2301.   -- ..................................
  2302.   function Current_Page
  2303.     ( Item           : in File )
  2304.       return Page_Number is
  2305.  
  2306.   --| Notes (none)
  2307.  
  2308.   begin -- Current_Page
  2309.  
  2310.     if not Item.Output_Is_Open then
  2311.       raise File_Not_Open;
  2312.     end if;
  2313.     return Item.Page_Num;
  2314.  
  2315.   end Current_Page;
  2316.  
  2317.   -- ..................................
  2318.   -- .                                .
  2319.   -- .  Current_Page                  .  BODY
  2320.   -- .                                .
  2321.   -- ..................................
  2322.   function Current_Page
  2323.     ( Item           : in FILE )
  2324.       return STRING is
  2325.  
  2326.   --| Notes (none)
  2327.  
  2328.     -- ..................................
  2329.     -- .                                .
  2330.     -- .  Current_Page.Convert          .  SPEC & BODY
  2331.     -- .                                .
  2332.     -- ..................................
  2333.     function Convert
  2334.       ( Page_Number : in STRING )
  2335.         return STRING is
  2336.  
  2337.       Result : STRING(1..80);
  2338.       Last : NATURAL := 0;
  2339.  
  2340.       -- ..................................
  2341.       -- .                                .
  2342.       -- .  Current_Page.Convert.Enter    .  SPEC & BODY
  2343.       -- .                                .
  2344.       -- ..................................
  2345.       procedure Enter
  2346.         ( Item : in STRING ) is
  2347.  
  2348.         Start : NATURAL := Item'First;
  2349.  
  2350.       begin -- Enter
  2351.  
  2352.         if Item(Start) = ' ' then
  2353.           Start := Start + 1;
  2354.         end if;
  2355.         for I in Start .. Item'Last loop
  2356.           Last := Last + 1;
  2357.           Result(Last) := Item(I);
  2358.         end loop;
  2359.  
  2360.       end Enter;
  2361.  
  2362.     begin -- Convert
  2363.  
  2364.       for I in Page_Number'Range loop
  2365.         if Page_Number(I) /= Item.Page_Number_Id then
  2366.           Last := Last + 1;
  2367.           Result(Last) := Page_Number(I);
  2368.         else
  2369.           Enter(Pnum_As_String(Item.Page_Num, Item.Pn_Format));
  2370.         end if;
  2371.       end loop;
  2372.       return Result(1..Last);
  2373.  
  2374.     end Convert;
  2375.  
  2376.   begin -- Current_Page
  2377.  
  2378.     if not Item.Output_Is_Open then
  2379.       raise File_Not_Open;
  2380.     end if;
  2381.     return Convert(FOF_DYN.Str(Item.Pn_String));
  2382.  
  2383.   end Current_Page;
  2384.  
  2385.   -- ..................................
  2386.   -- .                                .
  2387.   -- .  Set_Page_Number_Format        .  BODY
  2388.   -- .                                .
  2389.   -- ..................................
  2390.   procedure Set_Page_Number_Format
  2391.     ( Item           : in File;
  2392.       To             : in NUMERIC_FORMAT;
  2393.       Format_String  : in STRING ) is
  2394.  
  2395.   --| Notes (none)
  2396.  
  2397.   begin -- Set_Page_Number_Format
  2398.  
  2399.     if not Item.Output_Is_Open then
  2400.       raise File_Not_Open;
  2401.     end if;
  2402.     Item.Pn_Format := To;
  2403.     if Format_String'Length > 0 then
  2404.       FOF_DYN.Clear(Item.Pn_String);
  2405.       Item.Pn_String := FOF_DYN.D_String(Format_String);
  2406.     end if;
  2407.  
  2408.   end Set_Page_Number_Format;
  2409.  
  2410.   -- ..................................
  2411.   -- .                                .
  2412.   -- .  Set_Page_Attribute            .  BODY
  2413.   -- .                                .
  2414.   -- ..................................
  2415.   procedure Set_Page_Attribute
  2416.     ( Item           : in File;
  2417.       What           : in Page_Attribute;
  2418.       To             : in NATURAL ) is
  2419.  
  2420.   --| Notes (none)
  2421.  
  2422.   begin -- Set_Page_Attribute
  2423.  
  2424.     if not Item.Output_Is_Open then
  2425.       raise File_Not_Open;
  2426.     end if;
  2427.     Item.Page_Attr(What) := To;
  2428.  
  2429.   end Set_Page_Attribute;
  2430.  
  2431.   -- ..................................
  2432.   -- .                                .
  2433.   -- .  Set_Line_Attribute            .  BODY
  2434.   -- .                                .
  2435.   -- ..................................
  2436.   procedure Set_Line_Attribute
  2437.     ( Item           : in File;
  2438.       What           : in Line_Attribute;
  2439.       To             : in Off_On ) is
  2440.  
  2441.   --| Notes (none)
  2442.  
  2443.   begin -- Set_Line_Attribute
  2444.  
  2445.     if not Item.Output_Is_Open then
  2446.       raise File_Not_Open;
  2447.     end if;
  2448.     Item.Line_Attr(What) := To;
  2449.     if What = CENTER then
  2450.       if To = On then
  2451.         Item.Line_Attr(Fill_State_Before_Center) := Item.Line_Attr(Fill);
  2452.         Item.Line_Attr(Fill) := Off;
  2453.       else
  2454.         Item.Line_Attr(Fill) := Item.Line_Attr(Fill_State_Before_Center);
  2455.       end if;
  2456.     end if;
  2457.  
  2458.   end Set_Line_Attribute;
  2459.  
  2460.   -- ..................................
  2461.   -- .                                .
  2462.   -- .  Get_Page_Attribute            .  BODY
  2463.   -- .                                .
  2464.   -- ..................................
  2465.   function Get_Page_Attribute
  2466.     ( Item           : in File;
  2467.       What           : in Page_Attribute )
  2468.       return NATURAL is
  2469.  
  2470.   --| Notes (none)
  2471.  
  2472.   begin -- Get_Page_Attribute
  2473.  
  2474.     if not Item.Output_Is_Open then
  2475.       raise File_Not_Open;
  2476.     end if;
  2477.     return Item.Page_Attr(What);
  2478.  
  2479.   end Get_Page_Attribute;
  2480.  
  2481.   -- ..................................
  2482.   -- .                                .
  2483.   -- .  Get_Line_Attribute            .  BODY
  2484.   -- .                                .
  2485.   -- ..................................
  2486.   function Get_Line_Attribute
  2487.     ( Item           : in File;
  2488.       What           : in Line_Attribute )
  2489.       return Off_On is
  2490.  
  2491.   --| Notes (none)
  2492.  
  2493.   begin -- Get_Line_Attribute
  2494.  
  2495.     if not Item.Output_Is_Open then
  2496.       raise File_Not_Open;
  2497.     end if;
  2498.     return Item.Line_Attr(What);
  2499.  
  2500.   end Get_Line_Attribute;
  2501.  
  2502.   -- ..................................
  2503.   -- .                                .
  2504.   -- .  Test_Page                     .  BODY
  2505.   -- .                                .
  2506.   -- ..................................
  2507.   function Test_Page
  2508.     ( Item           : in File;
  2509.       Number_Of_Lines : in Line_Number )
  2510.       return BOOLEAN is
  2511.  
  2512.   --| Notes (none)
  2513.  
  2514.   begin -- Test_Page
  2515.  
  2516.     if not Item.Output_Is_Open then
  2517.       raise File_Not_Open;
  2518.     end if;
  2519.     return INTEGER(Number_Of_Lines) <= Item.Page_Attr(Total_Lines) - (Item.
  2520.         Page_Attr(Bottom_Margin) + Item.Page_Attr(Footer_Lines))
  2521.         - INTEGER(Item.Line_Num);
  2522.  
  2523.   end Test_Page;
  2524.  
  2525.   -- ..................................
  2526.   -- .                                .
  2527.   -- .  Set_Footer_Line               .  BODY
  2528.   -- .                                .
  2529.   -- ..................................
  2530.   procedure Set_Footer_Line
  2531.     ( Item           : in File;
  2532.       Class          : in Page_Kind;
  2533.       Number         : in Header_Footer_Line;
  2534.       Left_Text      : in STRING;
  2535.       Center_Text    : in STRING;
  2536.       Right_Text     : in STRING ) is
  2537.  
  2538.   --| Notes (none)
  2539.  
  2540.   begin -- Set_Footer_Line
  2541.  
  2542.     if not Item.Output_Is_Open then
  2543.       raise File_Not_Open;
  2544.     end if;
  2545.     case Class is
  2546.       when Even_Pages =>
  2547.         FOF_DYN.Clear(Item.Even_Footer(Number, LEFT));
  2548.         Item.Even_Footer(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2549.         FOF_DYN.Clear(Item.Even_Footer(Number, CENTER));
  2550.         Item.Even_Footer(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2551.         FOF_DYN.Clear(Item.Even_Footer(Number, RIGHT));
  2552.         Item.Even_Footer(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2553.       when Odd_Pages =>
  2554.         FOF_DYN.Clear(Item.Odd_Footer(Number, LEFT));
  2555.         Item.Odd_Footer(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2556.         FOF_DYN.Clear(Item.Odd_Footer(Number, CENTER));
  2557.         Item.Odd_Footer(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2558.         FOF_DYN.Clear(Item.Odd_Footer(Number, RIGHT));
  2559.         Item.Odd_Footer(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2560.       when All_Pages =>
  2561.         FOF_DYN.Clear(Item.Even_Footer(Number, LEFT));
  2562.         Item.Even_Footer(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2563.         FOF_DYN.Clear(Item.Even_Footer(Number, CENTER));
  2564.         Item.Even_Footer(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2565.         FOF_DYN.Clear(Item.Even_Footer(Number, RIGHT));
  2566.         Item.Even_Footer(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2567.         FOF_DYN.Clear(Item.Odd_Footer(Number, LEFT));
  2568.         Item.Odd_Footer(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2569.         FOF_DYN.Clear(Item.Odd_Footer(Number, CENTER));
  2570.         Item.Odd_Footer(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2571.         FOF_DYN.Clear(Item.Odd_Footer(Number, RIGHT));
  2572.         Item.Odd_Footer(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2573.     end case;
  2574.  
  2575.   exception
  2576.     when others =>
  2577.       FOF_Error_Log.Write_Error(Error_Internal_Set_Footer_Line);
  2578.  
  2579.   end Set_Footer_Line;
  2580.  
  2581.   -- ..................................
  2582.   -- .                                .
  2583.   -- .  Set_Header_Line               .  BODY
  2584.   -- .                                .
  2585.   -- ..................................
  2586.   procedure Set_Header_Line
  2587.     ( Item           : in File;
  2588.       Class          : in Page_Kind;
  2589.       Number         : in Header_Footer_Line;
  2590.       Left_Text      : in STRING;
  2591.       Center_Text    : in STRING;
  2592.       Right_Text     : in STRING ) is
  2593.  
  2594.   --| Notes (none)
  2595.  
  2596.   begin -- Set_Header_Line
  2597.  
  2598.     if not Item.Output_Is_Open then
  2599.       raise File_Not_Open;
  2600.     end if;
  2601.     case Class is
  2602.       when Even_Pages =>
  2603.         FOF_DYN.Clear(Item.Even_Header(Number, LEFT));
  2604.         Item.Even_Header(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2605.         FOF_DYN.Clear(Item.Even_Header(Number, CENTER));
  2606.         Item.Even_Header(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2607.         FOF_DYN.Clear(Item.Even_Header(Number, RIGHT));
  2608.         Item.Even_Header(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2609.       when Odd_Pages =>
  2610.         FOF_DYN.Clear(Item.Odd_Header(Number, LEFT));
  2611.         Item.Odd_Header(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2612.         FOF_DYN.Clear(Item.Odd_Header(Number, CENTER));
  2613.         Item.Odd_Header(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2614.         FOF_DYN.Clear(Item.Odd_Header(Number, RIGHT));
  2615.         Item.Odd_Header(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2616.       when All_Pages =>
  2617.         FOF_DYN.Clear(Item.Even_Header(Number, LEFT));
  2618.         Item.Even_Header(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2619.         FOF_DYN.Clear(Item.Even_Header(Number, CENTER));
  2620.         Item.Even_Header(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2621.         FOF_DYN.Clear(Item.Even_Header(Number, RIGHT));
  2622.         Item.Even_Header(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2623.         FOF_DYN.Clear(Item.Odd_Header(Number, LEFT));
  2624.         Item.Odd_Header(Number, LEFT) := FOF_DYN.D_String(Left_Text);
  2625.         FOF_DYN.Clear(Item.Odd_Header(Number, CENTER));
  2626.         Item.Odd_Header(Number, CENTER) := FOF_DYN.D_String(Center_Text);
  2627.         FOF_DYN.Clear(Item.Odd_Header(Number, RIGHT));
  2628.         Item.Odd_Header(Number, RIGHT) := FOF_DYN.D_String(Right_Text);
  2629.     end case;
  2630.  
  2631.   exception
  2632.     when others =>
  2633.       FOF_Error_Log.Write_Error(Error_Internal_Set_Header_Line);
  2634.  
  2635.   end Set_Header_Line;
  2636.  
  2637.   -- ..................................
  2638.   -- .                                .
  2639.   -- .  Set_Page_Number_Id            .  BODY
  2640.   -- .                                .
  2641.   -- ..................................
  2642.   procedure Set_Page_Number_Id
  2643.     ( Item           : in File;
  2644.       To             : in CHARACTER ) is
  2645.  
  2646.   --| Notes (none)
  2647.  
  2648.   begin -- Set_Page_Number_Id
  2649.  
  2650.     if not Item.Output_Is_Open then
  2651.       raise File_Not_Open;
  2652.     end if;
  2653.     Item.Page_Number_Id := To;
  2654.  
  2655.   end Set_Page_Number_Id;
  2656.  
  2657.   -- ..................................
  2658.   -- .                                .
  2659.   -- .  Set_Page_Number_Format        .  BODY
  2660.   -- .                                .
  2661.   -- ..................................
  2662.   procedure Set_Page_Number_Format
  2663.     ( Item           : in File;
  2664.       To             : in Numeric_Format ) is
  2665.  
  2666.   --| Notes (none)
  2667.  
  2668.   begin -- Set_Page_Number_Format
  2669.  
  2670.     if not Item.Output_Is_Open then
  2671.       raise File_Not_Open;
  2672.     end if;
  2673.     Item.Pn_Format := To;
  2674.  
  2675.   end Set_Page_Number_Format;
  2676.  
  2677.   -- ..................................
  2678.   -- .                                .
  2679.   -- .  Page_Number_Format            .  BODY
  2680.   -- .                                .
  2681.   -- ..................................
  2682.   function Page_Number_Format
  2683.     ( Item           : in FILE )
  2684.     return NUMERIC_FORMAT is
  2685.  
  2686.   --| Notes (none)
  2687.  
  2688.   begin -- Page_Number_Format
  2689.  
  2690.     if not Item.Output_Is_Open then
  2691.       raise File_Not_Open;
  2692.     end if;
  2693.     return Item.Pn_Format;
  2694.  
  2695.   end Page_Number_Format;
  2696.  
  2697. end Formatted_Output_File;
  2698. --::::::::::
  2699. --hashfcns.bdy
  2700. --::::::::::
  2701. with unchecked_conversion;
  2702.  
  2703. package body hashing_functions_pkg is
  2704.     
  2705.     function hash_string(s: string) return natural is
  2706.  
  2707.     type word is array(1..32) of boolean; 
  2708.  
  2709.     function word_to_int is new 
  2710.         unchecked_conversion(source => word, target => integer); 
  2711.  
  2712.     chars_per_word: constant := 4; 
  2713.     subtype word_str is string(1..chars_per_word); 
  2714.  
  2715.     function word_str_to_word is new 
  2716.         unchecked_conversion(source => word_str, target => word);
  2717.  
  2718.     words_in_s: natural;
  2719.     left_over: natural;
  2720.    
  2721.     hash_word: word := (word'range => false);
  2722.  
  2723.     hack_word_str: word_str;   --Decbug
  2724.     hack_word: word;       --Decbug
  2725.     result1: integer;       --Decbug
  2726.     result2: natural;        --Decbug
  2727.  
  2728.     begin
  2729.     words_in_s := s'length/chars_per_word;
  2730.     left_over := s'length mod chars_per_word;
  2731.  
  2732. --Decbugs replacement: 
  2733.     for i in 1..words_in_s loop
  2734.         hack_word_str :=  s(s'first + chars_per_word * (i - 1) .. 
  2735.                 s'first + chars_per_word * i - 1);          
  2736.         hack_word := word_str_to_word(hack_word_str);
  2737.         hash_word := hash_word xor hack_word;        
  2738. --        hash_word := 
  2739. --        hash_word xor 
  2740. --        word_str_to_word(s(s'first + chars_per_word * (i - 1) ..
  2741. --                   s'first + chars_per_word * i - 1)); 
  2742.     end loop;
  2743.  
  2744. -- Decbug Replacements: 
  2745.         hack_word_str(1..left_over) := 
  2746.         s(s'first + chars_per_word * words_in_s .. s'last);
  2747.         hack_word := word_str_to_word(hack_word_str);    
  2748.         hash_word(1..left_over) :=         
  2749.         hash_word(1..left_over) xor hack_word(1..left_over); 
  2750.  
  2751. --    hash_word(1..left_over) := 
  2752. --        hash_word(1..left_over) xor
  2753. --        word_str_to_word(s(s'first + chars_per_word * words_in_s..s'last));
  2754.  
  2755.     result1 := word_to_int(hash_word); 
  2756.     result2 := result1 mod prime_num; 
  2757.     return result2; 
  2758.  
  2759. --    return word_to_int(hash_word) mod prime_num;
  2760.     end hash_string; 
  2761.  
  2762. end hashing_functions_pkg; 
  2763. --::::::::::
  2764. --in.bdy
  2765. --::::::::::
  2766. -- **********************************
  2767. -- *                                *
  2768. -- *  Input_File                    *  BODY
  2769. -- *                                *
  2770. -- **********************************
  2771. with Text_IO;
  2772. package body Input_File is
  2773.  
  2774. --| Notes (none)
  2775. --|
  2776. --| Modifications
  2777. --| 08/16/89  Rick Conn    Initial Version
  2778.  
  2779.   type FILE_OBJECT is
  2780.     record
  2781.       Is_Open        : BOOLEAN      := false;
  2782.       File           : Text_IO.File_Type;
  2783.     end record;
  2784.  
  2785.   -- ..................................
  2786.   -- .                                .
  2787.   -- .  Open                          .  BODY
  2788.   -- .                                .
  2789.   -- ..................................
  2790.  
  2791.   procedure Open
  2792.     ( Id             : in out File_Type;
  2793.       File_Name      : in STRING ) is
  2794.  
  2795.   --| Notes (none)
  2796.  
  2797.   begin -- Open
  2798.  
  2799.     Id             := new FILE_OBJECT;
  2800.     Text_IO.Open(Id.File, Text_IO.In_File, File_Name);
  2801.     Id.Is_Open     := true;
  2802.  
  2803.   exception -- Open -- Open
  2804.     when others =>
  2805.       raise Cannot_Open_Input_File;
  2806.  
  2807.   end Open;
  2808.  
  2809.   -- ..................................
  2810.   -- .                                .
  2811.   -- .  Get_Line                      .  BODY
  2812.   -- .                                .
  2813.   -- ..................................
  2814.   procedure Get_Line
  2815.     ( Id             : in out File_Type;
  2816.       Item           : out STRING;
  2817.       Last           : out NATURAL ) is
  2818.  
  2819.   --| Notes (none)
  2820.  
  2821.   begin -- Get_Line
  2822.  
  2823.     if Id.Is_Open then
  2824.       Text_IO.Get_Line(Id.File, Item, Last);
  2825.     end if;
  2826.  
  2827.   exception -- Get_Line -- Get_Line
  2828.     when others =>
  2829.       raise Read_Error;
  2830.  
  2831.   end Get_Line;
  2832.  
  2833.   -- ..................................
  2834.   -- .                                .
  2835.   -- .  End_Of_File                   .  BODY
  2836.   -- .                                .
  2837.   -- ..................................
  2838.   function End_Of_File
  2839.     ( Id             : in File_Type )
  2840.       return BOOLEAN is
  2841.  
  2842.   --| Notes (none)
  2843.  
  2844.   begin -- End_Of_File
  2845.  
  2846.     if Id.Is_Open then
  2847.       return Text_IO.End_Of_File(Id.File);
  2848.     end if;
  2849.  
  2850.   exception -- End_Of_File -- End_Of_File
  2851.     when others =>
  2852.       raise Read_Error;
  2853.  
  2854.   end End_Of_File;
  2855.  
  2856.   -- ..................................
  2857.   -- .                                .
  2858.   -- .  Close                         .  BODY
  2859.   -- .                                .
  2860.   -- ..................................
  2861.   procedure Close
  2862.     ( Id             : in out File_Type ) is
  2863.  
  2864.   --| Notes (none)
  2865.  
  2866.   begin -- Close
  2867.  
  2868.     if Id.Is_Open then
  2869.       Text_IO.Close(Id.File);
  2870.     end if;
  2871.  
  2872.   end Close;
  2873.  
  2874. end Input_File;
  2875. --::::::::::
  2876. --lists.bdy
  2877. --::::::::::
  2878. with unchecked_deallocation;
  2879.  
  2880. package body Lists is
  2881.  
  2882.     procedure Free is new unchecked_deallocation (Cell, List);
  2883.  
  2884. --------------------------------------------------------------------------
  2885.  
  2886.    function Last (L: in     List) return List is
  2887.  
  2888.        Place_In_L:        List;
  2889.        Temp_Place_In_L:   List;
  2890.  
  2891.    --|  Link down the list L and return the pointer to the last element
  2892.    --| of L.  If L is null raise the EmptyList exception.
  2893.  
  2894.    begin
  2895.        if L = null then
  2896.            raise EmptyList;
  2897.        else
  2898.  
  2899.            --|  Link down L saving the pointer to the previous element in 
  2900.            --|  Temp_Place_In_L.  After the last iteration Temp_Place_In_L
  2901.            --|  points to the last element in the list.
  2902.  
  2903.            Place_In_L := L;
  2904.            while Place_In_L /= null loop
  2905.                Temp_Place_In_L := Place_In_L;
  2906.                Place_In_L := Place_In_L.Next;
  2907.            end loop;
  2908.            return Temp_Place_In_L;
  2909.        end if;
  2910.     end Last;
  2911.     
  2912.     
  2913. --------------------------------------------------------------------------
  2914.  
  2915.     procedure Attach (List1: in out List;
  2916.                       List2: in     List ) is
  2917.         EndOfList1: List;
  2918.  
  2919.     --| Attach List2 to List1. 
  2920.     --| If List1 is null return List2
  2921.     --| If List1 equals List2 then raise CircularList
  2922.     --| Otherwise get the pointer to the last element of List1 and change
  2923.     --| its Next field to be List2.
  2924.  
  2925.     begin
  2926.         if List1 = null then
  2927.         List1 := List2;
  2928.             return;
  2929.         elsif List1 = List2 then
  2930.             raise CircularList;
  2931.         else     
  2932.             EndOfList1 := Last (List1);
  2933.             EndOfList1.Next := List2;
  2934.         end if;
  2935.     end Attach;
  2936.  
  2937. --------------------------------------------------------------------------
  2938.  
  2939.    procedure Attach (L:       in out List;
  2940.                      Element: in     ItemType ) is
  2941.  
  2942.        NewEnd:    List;
  2943.  
  2944.    --| Create a list containing Element and attach it to the end of L
  2945.  
  2946.    begin
  2947.        NewEnd := new Cell'(Info => Element, Next => null);
  2948.        Attach (L, NewEnd);
  2949.    end;
  2950.  
  2951. --------------------------------------------------------------------------
  2952.  
  2953.    function Attach (Element1: in   ItemType;
  2954.                     Element2: in   ItemType ) return List is
  2955.        NewList: List;
  2956.  
  2957.    --| Create a new list containing the information in Element1 and
  2958.    --| attach Element2 to that list.
  2959.  
  2960.    begin
  2961.        NewList := new Cell'(Info => Element1, Next => null);
  2962.        Attach (NewList, Element2);
  2963.        return NewList;
  2964.    end;
  2965.  
  2966. --------------------------------------------------------------------------
  2967.  
  2968.    procedure Attach (Element: in     ItemType;
  2969.                      L:       in out List      ) is
  2970.  
  2971.    --|  Create a new cell whose information is Element and whose Next
  2972.    --|  field is the list L.  This prepends Element to the List L.
  2973.  
  2974.    begin
  2975.        L := new Cell'(Info => Element, Next => L);
  2976.    end;
  2977.  
  2978. --------------------------------------------------------------------------
  2979.  
  2980.    function Attach ( List1: in    List;
  2981.                      List2: in    List   ) return List is
  2982.  
  2983.    Last_Of_List1: List;
  2984.  
  2985.    begin 
  2986.        if List1 = null then
  2987.            return List2;
  2988.        elsif List1 = List2 then
  2989.            raise CircularList;
  2990.        else 
  2991.            Last_Of_List1 := Last (List1);
  2992.            Last_Of_List1.Next := List2;
  2993.            return List1;   
  2994.        end if;
  2995.    end  Attach;
  2996.  
  2997. -------------------------------------------------------------------------
  2998.  
  2999.    function Attach( L:       in     List;
  3000.                     Element: in     ItemType ) return List is
  3001.  
  3002.    NewEnd: List;
  3003.    Last_Of_L: List;
  3004.  
  3005.    --| Create a list called NewEnd and attach it to the end of L.
  3006.    --| If L is null return NewEnd 
  3007.    --| Otherwise get the last element in L and make its Next field
  3008.    --| NewEnd.
  3009.  
  3010.    begin 
  3011.        NewEnd := new Cell'(Info => Element, Next => null);
  3012.        if L = null then
  3013.            return NewEnd;
  3014.        else 
  3015.            Last_Of_L := Last (L);
  3016.            Last_Of_L.Next := NewEnd;
  3017.            return L;
  3018.        end if;
  3019.    end Attach;
  3020.  
  3021. --------------------------------------------------------------------------
  3022.  
  3023.    function Attach (Element: in     ItemType;
  3024.                     L:       in     List        ) return List is
  3025.  
  3026.    begin
  3027.        return (new Cell'(Info => Element, Next => L));
  3028.    end Attach;
  3029.  
  3030. ---------------------------------------------------------------------------
  3031.  
  3032.  
  3033.    function Copy (L: in     List) return List is
  3034.    
  3035.    --| If L is null return null
  3036.    --| Otherwise recursively copy the list by first copying the information
  3037.    --| at the head of the list and then making the Next field point to 
  3038.    --| a copy of the tail of the list.
  3039.  
  3040.    begin
  3041.        if L = null then
  3042.        return null;
  3043.        else
  3044.        return new Cell'(Info => L.Info, Next => Copy (L.Next));
  3045.        end if;
  3046.    end Copy;
  3047.  
  3048.  
  3049. --------------------------------------------------------------------------
  3050.  
  3051.    function CopyDeep (L: in List) return List is
  3052.        
  3053.    --|  If L is null then return null.
  3054.    --|  Otherwise copy the first element of the list into the head of the
  3055.    --|  new list and copy the tail of the list recursively using CopyDeep.
  3056.  
  3057.    begin
  3058.        if L = null then
  3059.        return null;
  3060.        else
  3061.        return new Cell'( Info => Copy (L.Info), Next => CopyDeep(L.Next));
  3062.        end if;
  3063.    end CopyDeep;
  3064.        
  3065. --------------------------------------------------------------------------
  3066.  
  3067.     function Create return List is
  3068.  
  3069.     --| Return the empty list.
  3070.  
  3071.     begin
  3072.         return null;
  3073.     end Create;
  3074.     
  3075. --------------------------------------------------------------------------
  3076.    procedure DeleteHead (L: in out List) is
  3077.  
  3078.        TempList: List;
  3079.  
  3080.    --| Remove the element of the head of the list and return it to the heap.
  3081.    --| If L is null EmptyList.
  3082.    --| Otherwise save the Next field of the first element, remove the first
  3083.    --| element and then assign to L the Next field of the first element.
  3084.  
  3085.    begin
  3086.        if L = null then
  3087.            raise EmptyList;
  3088.        else
  3089.            TempList := L.Next;
  3090.            Free (L);
  3091.            L := TempList;
  3092.        end if;
  3093.    end DeleteHead;
  3094.  
  3095. --------------------------------------------------------------------------
  3096.  
  3097. function DeleteItem(            --| remove the first occurrence of Element
  3098.                                 --| from L
  3099.       L:       in     List;     --| list element is being  removed from
  3100.       Element: in     ItemType  --| element being removed
  3101. ) return List is
  3102.     I       :List;
  3103.     Result  :List;
  3104.     Found   :boolean := false;
  3105. begin
  3106.     --| ALGORITHM
  3107.     --| Attach all elements of L to Result except the first element in L
  3108.     --| whose value is Element.  If the current element pointed to by I
  3109.     --| is not equal to element or the element being skipped was found
  3110.     --| then attach the current element to Result.
  3111.  
  3112.     I := L;
  3113.     while (I /= null) loop
  3114.         if (not Equal (I.Info, Element)) or (Found) then
  3115.             Attach (Result, I.Info);
  3116.         else
  3117.            Found := true;
  3118.         end if;
  3119.         I := I.Next;
  3120.     end loop;
  3121.     return Result;
  3122. end DeleteItem;
  3123.  
  3124. ------------------------------------------------------------------------------
  3125.  
  3126. function DeleteItems (          --| remove all occurrences of Element
  3127.                                 --| from  L.
  3128.       L:       in     List;     --| The List element is being removed from
  3129.       Element: in     ItemType  --| element being removed
  3130. ) return List is
  3131.     I       :List;
  3132.     Result  :List;
  3133. begin
  3134.     --| ALGORITHM
  3135.     --| Walk over the list L and if the current element does not equal 
  3136.     --| Element then attach it to the list to be returned.
  3137.  
  3138.     I := L;
  3139.     while I /= null loop
  3140.         if not Equal (I.Info, Element) then
  3141.             Attach (Result, I.Info);
  3142.         end if;
  3143.         I := I.Next;
  3144.     end loop;
  3145.     return Result;
  3146. end DeleteItems;
  3147.  
  3148. -------------------------------------------------------------------------------
  3149.  
  3150.    procedure DeleteItem (L:       in out List;
  3151.                          Element: in     ItemType ) is
  3152.  
  3153.        Temp_L  :List;
  3154.  
  3155.    --| Remove the first element in the list with the value Element.
  3156.    --| If the first element of the list is equal to element then
  3157.    --| remove it.  Otherwise, recurse on the tail of the list.
  3158.  
  3159.    begin
  3160.        if Equal(L.Info, Element) then
  3161.            DeleteHead(L);
  3162.        else
  3163.            DeleteItem(L.Next, Element);
  3164.        end if; 
  3165.    end DeleteItem;
  3166.  
  3167. --------------------------------------------------------------------------
  3168.  
  3169.    procedure DeleteItems (L:       in out List;
  3170.                           Element: in     ItemType ) is
  3171.  
  3172.        Place_In_L       :List;     --| Current place in L.
  3173.        Last_Place_In_L  :List;     --| Last place in L.
  3174.        Temp_Place_In_L  :List;     --| Holds a place in L to be removed.
  3175.  
  3176.    --| Walk over the list removing all elements with the value Element.
  3177.  
  3178.    begin
  3179.        Place_In_L := L;
  3180.        Last_Place_In_L := null;
  3181.        while (Place_In_L /= null) loop
  3182.            --| Found an element equal to Element
  3183.            if Equal(Place_In_L.Info, Element) then
  3184.                 --| If Last_Place_In_L is null then we are at first element
  3185.                 --| in L.
  3186.                 if Last_Place_In_L = null then
  3187.                      Temp_Place_In_L := Place_In_L;
  3188.                      L := Place_In_L.Next;
  3189.                 else
  3190.                      Temp_Place_In_L := Place_In_L;
  3191.                
  3192.                      --| Relink the list Last's Next gets Place's Next
  3193.  
  3194.                      Last_Place_In_L.Next := Place_In_L.Next;
  3195.                 end if;
  3196.  
  3197.                 --| Move Place_In_L to the next position in the list.
  3198.                 --| Free the element.
  3199.                 --| Do not update the last element in the list it remains the
  3200.                 --| same. 
  3201.  
  3202.                 Place_In_L := Place_In_L.Next;                       
  3203.                 Free (Temp_Place_In_L);
  3204.            else
  3205.                 --| Update the last place in L and the place in L.
  3206.  
  3207.                 Last_Place_In_L := Place_In_L;
  3208.                 Place_In_L := Place_In_L.Next;                       
  3209.            end if;    
  3210.        end loop;
  3211.  
  3212.    --| If we have not found an element raise an exception.
  3213.  
  3214.    end DeleteItems;
  3215. ------------------------------------------------------------------------------
  3216.  
  3217.    procedure Destroy (L: in out List) is
  3218.  
  3219.        Place_In_L:  List;
  3220.        HoldPlace:   List;
  3221.  
  3222.    --| Walk down the list removing all the elements and set the list to
  3223.    --| the empty list. 
  3224.  
  3225.    begin
  3226.        Place_In_L := L;
  3227.        while Place_In_L /= null loop
  3228.            HoldPlace := Place_In_L;
  3229.            Place_In_L := Place_In_L.Next;
  3230.            Free (HoldPlace);
  3231.        end loop;
  3232.        L := null;
  3233.    end Destroy;
  3234.  
  3235. --------------------------------------------------------------------------
  3236.  
  3237.    procedure DestroyDeep (L: in out List) is
  3238.  
  3239.        Place_In_L:  List;
  3240.        HoldPlace:   List;
  3241.  
  3242.    --| Walk down the list removing all the elements and set the list to
  3243.    --| the empty list. 
  3244.  
  3245.    begin
  3246.        Place_In_L := L;
  3247.        while Place_In_L /= null loop
  3248.            HoldPlace := Place_In_L;
  3249.            Place_In_L := Place_In_L.Next;
  3250.            Dispose (HoldPlace.Info);
  3251.            Free (HoldPlace);
  3252.        end loop;
  3253.        L := null;
  3254.    end DestroyDeep;
  3255.  
  3256. --------------------------------------------------------------------------
  3257.  
  3258.    function FirstValue (L: in    List) return ItemType is
  3259.  
  3260.    --| Return the first value in the list.
  3261.  
  3262.    begin
  3263.        if L = null then
  3264.        raise EmptyList;
  3265.        else
  3266.            return (L.Info);
  3267.        end if;
  3268.    end FirstValue;
  3269.    
  3270. --------------------------------------------------------------------------
  3271.  
  3272.    procedure Forward (I: in out ListIter) is
  3273.  
  3274.    --| Return the pointer to the next member of the list.
  3275.  
  3276.    begin
  3277.        if I = null then 
  3278.            raise NoMore;
  3279.        else
  3280.            I := ListIter (I.Next);
  3281.        end if;
  3282.    end Forward;
  3283.    
  3284. --------------------------------------------------------------------------
  3285.  
  3286.    function IsInList (L:       in    List; 
  3287.                       Element: in    ItemType  ) return boolean is
  3288.  
  3289.    Place_In_L: List;
  3290.  
  3291.    --| Check if Element is in L.  If it is return true otherwise return false.
  3292.  
  3293.    begin
  3294.        Place_In_L := L;
  3295.        while Place_In_L /= null loop
  3296.        if Equal(Place_In_L.Info, Element) then
  3297.            return true;
  3298.        end if;
  3299.            Place_In_L := Place_In_L.Next;
  3300.     end loop;
  3301.     return false;
  3302.    end IsInList;
  3303.  
  3304. --------------------------------------------------------------------------
  3305.  
  3306.     function IsEmpty (L: in     List) return boolean is
  3307.     
  3308.     --| Is the list L empty.
  3309.  
  3310.     begin
  3311.     return (L = null);
  3312.     end IsEmpty;
  3313.     
  3314. --------------------------------------------------------------------------
  3315.  
  3316.    function LastValue (L: in     List) return ItemType is
  3317.        
  3318.        LastElement: List;
  3319.  
  3320.    --| Return the value of the last element of the list. Get the pointer
  3321.    --| to the last element of L and then return its information.
  3322.  
  3323.    begin
  3324.        LastElement := Last (L);
  3325.        return LastElement.Info;
  3326.    end LastValue;
  3327.        
  3328. --------------------------------------------------------------------------
  3329.  
  3330.    function Length (L: in     List) return integer is
  3331.  
  3332.    --| Recursively compute the length of L.  The length of a list is
  3333.    --| 0 if it is null or  1 + the length of the tail.
  3334.  
  3335.    begin
  3336.        if L = null then
  3337.            return (0);
  3338.        else
  3339.            return (1 + Length (Tail (L)));
  3340.        end if;
  3341.    end Length;
  3342.  
  3343. --------------------------------------------------------------------------
  3344.  
  3345.    function MakeList (
  3346.           E :in     ItemType
  3347.    ) return List is
  3348.  
  3349.    begin
  3350.        return new Cell ' (Info => E, Next => null);
  3351.    end;
  3352.  
  3353. --------------------------------------------------------------------------
  3354.    function MakeListIter (L: in     List) return ListIter is
  3355.    
  3356.    --| Start an iteration operation on the list L.  Do a type conversion
  3357.    --| from List to ListIter.
  3358.     
  3359.    begin
  3360.        return ListIter (L);
  3361.    end MakeListIter;
  3362.  
  3363. --------------------------------------------------------------------------
  3364.  
  3365.    function More (L: in     ListIter) return boolean is
  3366.  
  3367.    --| This is a test to see whether an iteration is complete.
  3368.   
  3369.    begin
  3370.        return L /= null;
  3371.    end;
  3372.  
  3373. --------------------------------------------------------------------------
  3374.  
  3375.    procedure Next (Place:   in out ListIter;
  3376.                    Info:       out ItemType ) is
  3377.        PlaceInList: List;
  3378.    
  3379.    --| This procedure gets the information at the current place in the List
  3380.    --| and moves the ListIter to the next postion in the list.
  3381.    --| If we are at the end of a list then exception NoMore is raised.
  3382.  
  3383.    begin
  3384.        if Place = null then
  3385.       raise NoMore;
  3386.        else
  3387.           PlaceInList := List(Place);  
  3388.           Info := PlaceInList.Info;
  3389.           Place := ListIter(PlaceInList.Next);
  3390.        end if;
  3391.    end Next;
  3392.  
  3393. --------------------------------------------------------------------------
  3394.  
  3395.    procedure ReplaceHead (L:    in out  List;
  3396.                           Info: in      ItemType ) is
  3397.  
  3398.    --| This procedure replaces the information at the head of a list
  3399.    --| with the given information. If the list is empty the exception
  3400.    --| EmptyList is raised.
  3401.  
  3402.    begin
  3403.        if L = null then
  3404.        raise EmptyList;
  3405.        else
  3406.            L.Info := Info;
  3407.        end if;
  3408.    end ReplaceHead;
  3409.  
  3410. --------------------------------------------------------------------------
  3411.  
  3412.    procedure ReplaceTail (L:        in out List;
  3413.                           NewTail:  in     List  ) is
  3414.        Temp_L: List;
  3415.    
  3416.    --| This destroys the tail of a list and replaces the tail with
  3417.    --| NewTail.  If L is empty EmptyList is raised.
  3418.  
  3419.    begin
  3420.        Destroy(L.Next); 
  3421.        L.Next := NewTail; 
  3422.    exception
  3423.        when constraint_error =>
  3424.            raise EmptyList;
  3425.    end ReplaceTail;
  3426.  
  3427. --------------------------------------------------------------------------
  3428.  
  3429.     function Tail (L: in    List) return List is
  3430.  
  3431.     --| This returns the list which is the tail of L.  If L is null 
  3432.     --| EmptyList is raised.
  3433.  
  3434.     begin
  3435.     if L = null then
  3436.         raise EmptyList;
  3437.     else
  3438.         return L.Next;
  3439.     end if;
  3440.     end Tail;
  3441.  
  3442. --------------------------------------------------------------------------
  3443.  
  3444.     function CellValue (     
  3445.            I :in ListIter
  3446.     ) return ItemType is
  3447.         L :List;
  3448.     begin
  3449.           -- Convert I to a List type and then return the value it points to.
  3450.         L := List(I);
  3451.         return L.Info;
  3452.     end CellValue;
  3453.  
  3454. --------------------------------------------------------------------------
  3455.     function Equal (List1: in    List;
  3456.                     List2: in    List ) return boolean is
  3457.  
  3458.         PlaceInList1: List;
  3459.         PlaceInList2: LIst;
  3460.     Contents1:    ItemType;
  3461.     Contents2:    ItemType;
  3462.  
  3463.     --| This function tests to see if two lists are equal.  Two lists
  3464.     --| are equal if for all the elements of List1 the corresponding
  3465.     --| element of List2 has the same value.  Thus if the 1st elements
  3466.     --| are equal and the second elements are equal and so up to n.
  3467.     --|  Thus a necessary condition for two lists to be equal is that
  3468.     --| they have the same number of elements.
  3469.  
  3470.     --| This function walks over the two list and checks that the
  3471.     --| corresponding elements are equal.  As soon as we reach 
  3472.     --| the end of a list (PlaceInList = null) we fall out of the loop.
  3473.     --| If both PlaceInList1 and PlaceInList2 are null after exiting the loop
  3474.     --| then the lists are equal.  If they both are not null the lists aren't 
  3475.     --| equal.  Note that equality on elements is based on a user supplied
  3476.     --| function Equal which is used to test for item equality.
  3477.  
  3478.     begin
  3479.         PlaceInList1 := List1;
  3480.         PlaceInList2 := List2;
  3481.         while   (PlaceInList1 /= null) and (PlaceInList2 /= null) loop
  3482.             if not Equal (PlaceInList1.Info, PlaceInList2.Info) then
  3483.                 return false;
  3484.             end if;
  3485.         PlaceInList1 := PlaceInList1.Next;
  3486.         PlaceInList2 := PlaceInList2.Next;
  3487.         end loop;
  3488.         return ((PlaceInList1 = null) and (PlaceInList2 = null) );
  3489.     end Equal;
  3490. end Lists;
  3491.  
  3492. --------------------------------------------------------------------------
  3493. --::::::::::
  3494. --logical.bdy
  3495. --::::::::::
  3496. package body logical is
  3497.  
  3498.    -- These functions work on all two's complement machines
  3499.    -- where -integer'last-1 = integer'first
  3500.  
  3501.    two_to_the_i : array(integer(0)..integer(integer'size-1)) of integer;
  3502.  
  3503.    --Utility function to rotate left
  3504.    function rotate(arg, count : integer) return integer is
  3505.       result : integer := arg;
  3506.       big      : CONSTANT integer := integer'last/2+1;
  3507.       c        : integer := count;
  3508.    begin
  3509.       if c < 0 then
  3510.          c := integer'size + c;
  3511.       end if;
  3512.       for i in 1..(c MOD integer'size) loop
  3513.      if result < 0 then                     -- -16#80000000#..-1
  3514.         result := result + big;
  3515.         if result >= 0 then
  3516.            result := result * 2 - integer'last;
  3517.         else
  3518.            result := (result + big) * 2 + 1;
  3519.         end if;
  3520.      elsif result < big then       -- 0 .. 16#3FFFFFFF#
  3521.         result := result * 2;
  3522.      else                          -- 16#40000000#..16#7FFFFFFF#
  3523.         result := (result - big) * 2 - integer'last;
  3524.             result := result - 1;
  3525.      end if;
  3526.       end loop;
  3527.       return result;
  3528.    end rotate;
  3529.    --
  3530.    --Utility function to logical shift
  3531.    function shift(arg, count : integer) return integer is
  3532.       result : integer := arg;
  3533.       big      : CONSTANT integer := integer'last/2+1;
  3534.       c        : integer;
  3535.    begin -- shift
  3536.       if count < 0 then                  --shift to the right
  3537.          c := -count;
  3538.          if c >= integer'size then
  3539.             return 0;
  3540.          end if;
  3541.      if result >= 0 then
  3542.         result := result / two_to_the_i(c);
  3543.      else
  3544.             result := result + integer'last;
  3545.         result := (result + 1) / two_to_the_i(c) +
  3546.               big / two_to_the_i(c - 1);
  3547.      end if;
  3548.       elsif count > 0 then                --shift to the left
  3549.          if count >= integer'size then
  3550.             return 0;
  3551.          end if;
  3552.          for i in 1..count loop
  3553.             if result < 0 then   --top bit gets shifted out
  3554.                result := result + integer'last;
  3555.                result := result + 1;
  3556.             end if;
  3557.             if result >= big then
  3558.                result := ((result - big) * 2 - integer'last);
  3559.                result := result - 1;
  3560.             else
  3561.                result := result * 2;
  3562.             end if;
  3563.          end loop;
  3564.       end if;
  3565.       return result;
  3566.    end shift;
  3567.    --
  3568.    --Utility function to logical shift right 1
  3569.    function shift_right_1(arg : integer) return integer is
  3570.       result : integer := arg;
  3571.       big      : CONSTANT integer := integer'last/2+1;
  3572.    begin -- shift_right_1
  3573.       if result >= 0 then
  3574.      result := result / 2;
  3575.       else
  3576.          result := result + integer'last;
  3577.      result := (result + 1) / 2 + big;
  3578.       end if;
  3579.       return result;
  3580.    end shift_right_1;
  3581.    --
  3582.    --Utility function to exclusive or
  3583.    function "xor"(left, right : integer) return integer is
  3584.       result : integer := 0;
  3585.       a1 : integer := left;
  3586.       a2 : integer := right;
  3587.    begin -- "xor"
  3588.       for i in integer(0)..integer'size-1 loop
  3589.      result := shift_right_1(result);
  3590.      if a1 MOD 2 /= a2 MOD 2 then
  3591.             result := result - integer'last;
  3592.         result := result - 1;
  3593.      end if;
  3594.      a1 := shift_right_1(a1);
  3595.      a2 := shift_right_1(a2);
  3596.       end loop;
  3597.       return result;
  3598.    end "xor";
  3599.    --
  3600.    --Utility function to and
  3601.    function "and"(left, right : integer) return integer is
  3602.       result : integer := 0;
  3603.       a1 : integer := left;
  3604.       a2 : integer := right;
  3605.    begin -- "and"
  3606.       for i in integer(0)..integer'size-1 loop
  3607.      result := shift_right_1(result);
  3608.      if (a1 MOD 2) + (a2 MOD 2) = 2 then
  3609.             result := result - integer'last;
  3610.         result := result - 1;
  3611.      end if;
  3612.      a1 := shift_right_1(a1);
  3613.      a2 := shift_right_1(a2);
  3614.       end loop;
  3615.       return result;
  3616.    end "and";
  3617.    --
  3618.    --Utility function to or
  3619.    function "or"(left, right : integer) return integer is
  3620.       result : integer := 0;
  3621.       a1 : integer := left;
  3622.       a2 : integer := right;
  3623.    begin -- "or"
  3624.       for i in integer(0)..integer'size-1 loop
  3625.      result := shift_right_1(result);
  3626.      if (a1 MOD 2) + (a2 MOD 2) /= 0 then
  3627.             result := result - integer'last;
  3628.         result := result - 1;
  3629.      end if;
  3630.      a1 := shift_right_1(a1);
  3631.      a2 := shift_right_1(a2);
  3632.       end loop;
  3633.       return result;
  3634.    end "or";
  3635.    --
  3636.    function "not"(right : integer) return integer is
  3637.    begin
  3638.       if right /= integer'first and then
  3639.          right /= integer'first + 1 then
  3640.          return (-1)-right;
  3641.       else
  3642.          return -(right + 1);
  3643.       end if;
  3644.    end "not";
  3645.    --
  3646. begin
  3647.    for i in two_to_the_i'first..two_to_the_i'last-1 loop
  3648.       two_to_the_i(i) := 2**i;
  3649.    end loop;
  3650.    two_to_the_i(two_to_the_i'last) := (-2)**two_to_the_i'last;
  3651. end logical;
  3652. --::::::::::
  3653. --lparse.bdy
  3654. --::::::::::
  3655. package body LINE_PARSER is
  3656.    
  3657.    LOCAL_ARGC : NATURAL := 0; -- Number of tokens
  3658.    
  3659.    package STRING_LIST is
  3660.       
  3661.       NUMBER_OF_STRINGS : NATURAL := 0;
  3662.       
  3663.       procedure RESET;
  3664.       procedure ADD_TO_LIST (ITEM : in STRING);
  3665.       function GET_FROM_LIST (ITEM : in NATURAL) return STRING;
  3666.       
  3667.    end STRING_LIST;
  3668.    
  3669.    package body STRING_LIST is
  3670.       
  3671.       type DYNAMIC_STRING_OBJECT (LENGTH : NATURAL);
  3672.       type DYNAMIC_STRING is access DYNAMIC_STRING_OBJECT;
  3673.       type DYNAMIC_STRING_OBJECT (LENGTH : NATURAL) is 
  3674.          record
  3675.             DS   : STRING (1 .. LENGTH);
  3676.             NEXT : DYNAMIC_STRING;
  3677.          end record;
  3678.       
  3679.       FIRST : DYNAMIC_STRING := null;
  3680.       LAST  : DYNAMIC_STRING := null;
  3681.       
  3682.       procedure RESET is
  3683.          
  3684.          --========================= PDL ===========================
  3685.          --|ABSTRACT:
  3686.          --|    RESET initializes the list.
  3687.          --|DESIGN DESCRIPTION:
  3688.          --|    Set FIRST to NULL
  3689.          --|    Set LAST to NULL
  3690.          --|    Set NUMBER_OF_STRINGS to 0
  3691.          --=========================================================
  3692.          
  3693.       begin
  3694.          FIRST             := null;
  3695.          LAST              := null;
  3696.          NUMBER_OF_STRINGS := 0;
  3697.       end RESET;
  3698.       
  3699.       procedure ADD_TO_LIST (ITEM : in STRING) is
  3700.          
  3701.          --========================= PDL ===========================
  3702.          --|ABSTRACT:
  3703.          --|    ADD_TO_LIST adds the ITEM string to the linked list
  3704.          --|    of dynamic strings implemented by this package.
  3705.          --|DESIGN DESCRIPTION:
  3706.          --|    Create new DYNAMIC_STRING_OBJECT of the proper length
  3707.          --|    Set DS field of new object to the ITEM string
  3708.          --|    Set the NEXT field of the new object to NULL
  3709.          --|    If FIRST pointer is null
  3710.          --|      Set FIRST and LAST to point to the new object
  3711.          --|    Else
  3712.          --|      Set LAST.NEXT to point to the new object
  3713.          --|      Set LAST to point to the new object
  3714.          --|    End if
  3715.          --|    Increment NUMBER_OF_STRINGS
  3716.          --=========================================================
  3717.          
  3718.          TEMP : DYNAMIC_STRING;
  3719.       begin
  3720.          TEMP := new DYNAMIC_STRING_OBJECT (ITEM'LENGTH);
  3721.          TEMP.DS (1 .. ITEM'LENGTH) := ITEM;
  3722.          TEMP.NEXT                  := null;
  3723.          if FIRST = null then
  3724.             FIRST := TEMP;
  3725.             LAST  := TEMP;
  3726.          else
  3727.             LAST.NEXT := TEMP;
  3728.             LAST      := TEMP;
  3729.          end if;
  3730.          NUMBER_OF_STRINGS := NUMBER_OF_STRINGS + 1;
  3731.       end ADD_TO_LIST;
  3732.       
  3733.       function GET_FROM_LIST (ITEM : in NATURAL) return STRING is
  3734.          
  3735.          --========================= PDL ===========================
  3736.          --|ABSTRACT:
  3737.          --|    GET_FROM_LIST returns the ITEM string from the linked list
  3738.          --|    of dynamic strings implemented by this package.
  3739.          --|DESIGN DESCRIPTION:
  3740.          --|    If ITEM > 0
  3741.          --|        Advance to desired item
  3742.          --|    End If
  3743.          --|    Return the DS field of the desired item
  3744.          --=========================================================
  3745.          
  3746.          ROVER : DYNAMIC_STRING := FIRST;
  3747.       begin
  3748.          if ITEM > 0 then
  3749.             for I in 1 .. ITEM loop
  3750.                ROVER := ROVER.NEXT;
  3751.             end loop;
  3752.          end if;
  3753.          return ROVER.DS;
  3754.       end GET_FROM_LIST;
  3755.       
  3756.    end STRING_LIST;
  3757.    
  3758.    procedure INITIALIZE (ITEM : in STRING) is
  3759.       
  3760.       --========================= PDL ===========================
  3761.       --|ABSTRACT:
  3762.       --|    INITIALIZE parses the string ITEM and sets up the
  3763.       --|    internal variables and linked list.
  3764.       --|DESIGN DESCRIPTION:
  3765.       --|    Reset the STRING_LIST Package
  3766.       --|    Set CURRENT_STATE to LOOKING_FOR_TOKEN
  3767.       --|    Over number of characters in line, loop
  3768.       --|        Case CURRENT_STATE
  3769.       --|            When LOOKING_FOR_TOKEN
  3770.       --|                If character is not white-space
  3771.       --|                    Set CURRENT_STATE to IN_TOKEN
  3772.       --|                    If character is quote (")
  3773.       --|                        Set QUOTED to TRUE
  3774.       --|                        Set START to the character's index + 1
  3775.       --|                    Else
  3776.       --|                        Set QUOTED to FALSE
  3777.       --|                        Set START to the character's index
  3778.       --|                    End IF
  3779.       --|                End If
  3780.       --|            When IN_TOKEN
  3781.       --|                If QUOTED
  3782.       --|                    If character is quote (")
  3783.       --|                        Set STOP to the previous character's index
  3784.       --|                        Add slice from START to STOP to list
  3785.       --|                        Set CURRENT_STATE to LOOKING_FOR_TOKEN
  3786.       --|                    End If
  3787.       --|                ElsIF character is white-space
  3788.       --|                    Set STOP to the previous character's index
  3789.       --|                    Add slice from START to STOP to list
  3790.       --|                    Set CURRENT_STATE to LOOKING_FOR_TOKEN
  3791.       --|                End If
  3792.       --|        End Case
  3793.       --|    End Loop
  3794.       --|    If CURRENT_STATE is IN_TOKEN
  3795.       --|        Set STOP to the previous character's index
  3796.       --|        Add slice from START to STOP to list
  3797.       --|    End if
  3798.       --|    Set LOCAL_ARGC to NUMBER_OF_STRINGS
  3799.       --=========================================================
  3800.       
  3801.       START         : NATURAL;
  3802.       STOP          : NATURAL;
  3803.       QUOTED        : BOOLEAN;
  3804.       type STATE is (LOOKING_FOR_TOKEN, IN_TOKEN);
  3805.       CURRENT_STATE : STATE := LOOKING_FOR_TOKEN;
  3806.    begin
  3807.       STRING_LIST.RESET;
  3808.       if ITEM'LENGTH > 0 then
  3809.          for I in ITEM'RANGE loop
  3810.             case CURRENT_STATE is
  3811.                when LOOKING_FOR_TOKEN    =>
  3812.                   if ITEM (I) > ' ' then
  3813.                      CURRENT_STATE := IN_TOKEN;
  3814.                      if ITEM (I) = '"' then
  3815.                         QUOTED := TRUE;
  3816.                         START  := I;
  3817.                      else
  3818.                         QUOTED := FALSE;
  3819.                         START  := I;
  3820.                      end if;
  3821.                   end if;
  3822.                when IN_TOKEN   =>
  3823.                   if QUOTED then
  3824.                      if ITEM (I) = '"' then
  3825.                         STOP          := I;
  3826.                         STRING_LIST.ADD_TO_LIST (ITEM (START .. STOP));
  3827.                         CURRENT_STATE := LOOKING_FOR_TOKEN;
  3828.                      end if;
  3829.                   elsif ITEM (I) <= ' ' then
  3830.                      STOP          := I - 1;
  3831.                      STRING_LIST.ADD_TO_LIST (ITEM (START .. STOP));
  3832.                      CURRENT_STATE := LOOKING_FOR_TOKEN;
  3833.                   end if;
  3834.             end case;
  3835.          end loop;
  3836.          if CURRENT_STATE = IN_TOKEN then
  3837.             STOP := ITEM'LAST;
  3838.             STRING_LIST.ADD_TO_LIST (ITEM (START .. STOP));
  3839.          end if;
  3840.          LOCAL_ARGC := STRING_LIST.NUMBER_OF_STRINGS;
  3841.       else
  3842.          LOCAL_ARGC := 0;
  3843.       end if;
  3844.    end INITIALIZE;
  3845.    
  3846.    function ARGC return NATURAL is
  3847.       
  3848.       --========================= PDL ===========================
  3849.       --|ABSTRACT:
  3850.       --|    ARGC returns the count of the number of tokens.
  3851.       --|DESIGN DESCRIPTION:
  3852.       --|    Return LOCAL_ARGC (set by INITIALIZE)
  3853.       --=========================================================
  3854.       
  3855.    begin
  3856.       return LOCAL_ARGC;
  3857.    end ARGC;
  3858.    
  3859.    function ARGV (INDEX : in NATURAL) return STRING is
  3860.       
  3861.       --========================= PDL ===========================
  3862.       --|ABSTRACT:
  3863.       --|    ARGV returns the indicated argument string.
  3864.       --|DESIGN DESCRIPTION:
  3865.       --|    If INDEX is out of range, raise INVALID_INDEX
  3866.       --|    Return GET_FROM_LIST(INDEX)
  3867.       --=========================================================
  3868.       
  3869.    begin
  3870.       if INDEX < 0 or INDEX >= LOCAL_ARGC then
  3871.          raise INVALID_INDEX;
  3872.       end if;
  3873.       return STRING_LIST.GET_FROM_LIST (INDEX);
  3874.    exception
  3875.       when INVALID_INDEX  =>
  3876.          raise ;
  3877.       when others    =>
  3878.          raise UNEXPECTED_ERROR;
  3879.    end ARGV;
  3880.    
  3881. end LINE_PARSER;
  3882. --::::::::::
  3883. --matrix.bdy
  3884. --::::::::::
  3885. -- ****************************************************************
  3886. -- *                                                              *
  3887. -- *  Matrix_Package                                              *  BODY
  3888. -- *                                                              *
  3889. -- ****************************************************************
  3890. with text_io;
  3891. use  text_io;
  3892. package body MATRIX_PACKAGE is
  3893. --| Notes
  3894. --| Modifications by Art Adamson --
  3895. -- Mod by A. P. Adamson..July 1990..Added cross product of vectors. 
  3896. -- The added function Vector1 ** Vector2 return Vector3 is limited to 
  3897. -- 3-D vectors. Vector3 = Vector1 cross Vector2.
  3898. -- Mod by A. P. Adamson..Oct. 6, 1990..Added VEC2T, a 2D VECTOR subtype.
  3899. -- Mod by A. P. Adamson..Oct. 6, 1990..Added VEC3T, a 3D VECTOR subtype.
  3900. -- Mod by A. P. Adamson..Oct. 6, 1990..Added MATR2T, a VECTOR but with
  3901. -- elements of VEC2T rather than float.
  3902. -- Mod by A. P. Adamson..Oct. 6, 1990..Added +, an operation to add a float
  3903. -- to each term of a VECTOR.
  3904. -- Mod by A. P. Adamson..Oct. 6, 1990..Added *, an operation to multiply
  3905. -- each VEC2T of a MATR2T by a single float.
  3906. -- Mod by A. P. Adamson..Oct. 6, 1990..Added *, an operation to dot product
  3907. -- each VEC2T of a MATR2T by a single VEC2T.
  3908. -- Mod by A. P. Adamson..Oct. 15, 1990..Added JCROSS, an operation to cross
  3909. -- product a fictitious unit vector j in y direction with a VEC2T having
  3910. -- components only in the x and z directions. Result is a VEC2T. Used to 
  3911. -- allow direct translation of certain 3d vector formulas into 2d space.
  3912. -- Net effect is to rotate the vec2t 90 degrees CW.
  3913. -- Mod by A. P. Adamson..Oct. 15, 1990..Added + , an operation to add a 
  3914. -- VEC2T to each term of a MATR2T.
  3915. -- Mod by A. P. Adamson..Oct. 15, 1990..Added * , an operation to multiply
  3916. -- each term of a MATR2T by a correspunding float term from a vector.
  3917. -- Mod by A. P. Adamson..Oct. 15, 1990..Added + , an operation to add
  3918. -- corresponding VEC2T's of two MATR2T and return MATR2T.
  3919. -- Mod by A. P. Adamson..Nov. 3, 1990..Added ROTX and ROTY operations to
  3920. -- rotate a VEC2T 180 degrees about the X axis or the Y axis.
  3921. -- Mod by A. P. Adamson..Nov. 11, 1990..Added MAT4MULT operation to
  3922. -- column multiply 4 square input matricees (the 4 corner quarters of a larger
  3923. -- matrix) by a column vector and return a column vector. Useful when a matrix
  3924. -- is too large for the memory capacity.
  3925. -- Mod by A. P. Adamson..Jan. 1,  1991..Added aXbDOTj operation to 
  3926. -- give scalar = mag of A cross B for 2 VEC2T vectors.
  3927. -- VEC2T has no third dimensoin so the cross product is not possible.
  3928. -- Mod by A. P. Adamson..Jan. 1,  1991..Added GETTAN operation to get the TAN
  3929. -- of angle theta between 2 VEC2T vectors.
  3930. -- Mod by A. P. Adamson..Feb. 15,  1992..Added GETTAN operation protection
  3931. --for divide by 0 when angle = PI/2.
  3932.  
  3933.   ---
  3934.   function TRANSPOSE(A : MATRIX) return MATRIX is
  3935.     B : MATRIX(A'first(2)..A'last(2),A'first(1)..A'last(1)) ;
  3936.     --     ******************************************************************
  3937.     --   This function performs the tranpose of input matrix A
  3938.     -- ******************************************************************
  3939.   begin
  3940.     for I in A'range(2) loop
  3941.       for J in A'range(1) loop
  3942.         B(I,J) := A(J,I) ;
  3943.       end loop ;
  3944.     end loop ;
  3945.     return B ;
  3946.   end TRANSPOSE;
  3947.   ---
  3948.   function TRANSPOSE(A : VECTOR) return VECTOR is
  3949.     -- *****************************************************************
  3950.     --   This function returns the transpose of a vector. In programming
  3951.     --   a vector is always stored as one-dimensional array. Therefore,
  3952.     --        there is no difference between row vector and column vector.
  3953.     --        Thus, this function just returns the input vector (do nothing).
  3954.     -- *****************************************************************
  3955.   begin
  3956.     return A;
  3957.   end TRANSPOSE;
  3958.   ---
  3959.   function "+" (A : VECTOR; B : VECTOR) return VECTOR is
  3960.     C : VECTOR(A'first..A'last) ;
  3961.     -- **************************************************************
  3962.     --   This function performs the addition of vector A and vector B
  3963.     --    resulting in a vector. Comparability of dimensions is checked.
  3964.     -- **************************************************************
  3965.   begin
  3966.     if A'first /= B'first or A'last /= B'last then
  3967.       raise INCOMPARABLE_DIMENSION;
  3968.     end if ;
  3969.     for I in A'range loop
  3970.       C(I) := A(I)+B(I) ;
  3971.     end loop ;
  3972.     return C ;
  3973.   end "+";
  3974.   ---
  3975.   function "+" (A : float; B : VECTOR) return VECTOR is
  3976.     C : VECTOR(B'first..B'last) ;
  3977.     -- **************************************************************
  3978.     --   This function performs the addition of a FLOAT A to each term
  3979.     --        of vector B resulting in a vector.
  3980.     -- **************************************************************
  3981.   begin
  3982.     for I in B'range loop
  3983.       C(I) := A + B(I) ;
  3984.     end loop ;
  3985.     return C ;
  3986.   end "+";
  3987.  
  3988.   ---
  3989.   function "+" (A : MATRIX; B : MATRIX) return MATRIX is
  3990.     C : MATRIX(A'first(1)..A'last(1),A'first(2)..A'last(2)) ;
  3991.     -- *******************************************************************
  3992.     --   This function performs the addition of matrix A and matrix B
  3993.     --   resulting in a matrix. Comparability of dimensions is checked.
  3994.     -- *******************************************************************
  3995.   begin
  3996.     if (A'first(1) /= B'first(1) or A'last(1) /= B'last(1)) 
  3997.     or (A'first(2) /= B'first(2) or A'last(2) /= B'last(2)) then
  3998.       raise INCOMPARABLE_DIMENSION;
  3999.     end if ;
  4000.     for I in A'range(1) loop
  4001.       for J in A'range(2) loop
  4002.         C(I,J) := A(I,J)+B(I,J) ;
  4003.       end loop ;
  4004.     end loop ;
  4005.     return C ;
  4006.   end "+";
  4007.   --
  4008.   function "+" (A : VEC2T;  B : MATR2T) return MATR2T  is
  4009.     TEMP : MATR2T(B'range);
  4010.     --      **********************************************************************
  4011.     --       Vec2T added to, each term of MATR2T
  4012.     --      **********************************************************************
  4013.   begin
  4014.     for I in B'range loop
  4015.       TEMP(I) := A + B(I);
  4016.     end loop;
  4017.     return TEMP;
  4018.   end "+";
  4019.   --
  4020.   function "+" (A : MATR2T;  B : MATR2T) return MATR2T  is
  4021.     TEMP : MATR2T(B'range);
  4022.     --      **********************************************************************
  4023.     --       Vec2T added to, each term of MATR2T
  4024.     --      **********************************************************************
  4025.   begin
  4026.     for I in B'range loop
  4027.       TEMP(I) := A(I) + B(I);
  4028.     end loop;
  4029.     return TEMP;
  4030.   end "+";
  4031.   --
  4032.   function "-" (A : VECTOR; B : VECTOR) return VECTOR is
  4033.     C : VECTOR(A'first..A'last) ;
  4034.     -- ******************************************************************
  4035.     --   This function performs the subtraction of vector B from vector A
  4036.     --   resulting in a vector. Comparability of dimensions is checked.
  4037.     -- ******************************************************************
  4038.   begin
  4039.     if A'first /= B'first or A'last /= B'last then
  4040.       raise INCOMPARABLE_DIMENSION;
  4041.     end if ;
  4042.     for I in A'range loop
  4043.       C(I) := A(I)-B(I) ;
  4044.     end loop ;
  4045.     return C ;
  4046.   end "-";
  4047.   ---
  4048.   function "-" (A : MATRIX; B : MATRIX) return MATRIX is
  4049.     C : MATRIX(A'first(1)..A'last(1),A'first(2)..A'last(2)) ;
  4050.     -- ******************************************************************
  4051.     --   This function performs the subtraction of matrix B from matrix A
  4052.     --   resulting in a matrix. Comparability of dimensions is checked.
  4053.     -- ******************************************************************
  4054.   begin
  4055.     if (A'first(1) /= B'first(1) or A'last(1) /= B'last(1)) 
  4056.     or (A'first(2) /= B'first(2) or A'last(2) /= B'last(2)) then
  4057.       raise INCOMPARABLE_DIMENSION;
  4058.     end if ;
  4059.     for I in A'range(1) loop
  4060.       for J in A'range(2) loop
  4061.         C(I,J) := A(I,J)-B(I,J) ;
  4062.       end loop ;
  4063.     end loop ;
  4064.     return C ;
  4065.   end "-";
  4066.   ---
  4067.   function "*" (A:float; B:VECTOR) return VECTOR is
  4068.     C: VECTOR(B'first..B'last);
  4069.     -- ******************************************************************
  4070.     --   This function performs the scalar multiplication of a floating
  4071.     --   number A and a vector B resulting in a vector.
  4072.     -- ******************************************************************
  4073.   begin
  4074.     for I in B'range loop
  4075.       C(I):=A*B(I);
  4076.     end loop;
  4077.     return C ;
  4078.   end "*";
  4079.  
  4080.   ---
  4081.   function "*" (A:VECTOR; B:float) return VECTOR is
  4082.   begin
  4083.     -- ********************************************************************
  4084.     --   This function performs the scalar multiplication of a vector A and
  4085.     --   a floating number B resulting in a vector.
  4086.     -- ********************************************************************
  4087.     return B*A;
  4088.   end "*";
  4089.  
  4090.   ---
  4091.   function "*" (A : VECTOR; B : VECTOR) return float is
  4092.     S :float:=0.0;
  4093.     -- *******************************************************************
  4094.     --   This function performs the inner (dot) product of two vectors A
  4095.     --   and B resulting in a floating number.
  4096.     --   Comparability of dimensions is checked.
  4097.     -- *******************************************************************
  4098.   begin
  4099.     if A'first /= B'first or A'last /= B'last then
  4100.       raise INCOMPARABLE_DIMENSION;
  4101.     end if ;
  4102.     for I in A'range loop
  4103.       S := S+A(I)*B(I) ;
  4104.     end loop ;
  4105.     return S ;
  4106.   end "*";
  4107.   ---
  4108.   function "*" (A:MATRIX; B:VECTOR) return VECTOR is
  4109.     C:VECTOR(A'first(1)..A'last(1));
  4110.     SUM:float;
  4111.     -- **********************************************************************
  4112.     --   This function performs the multiplication of a matrix A and a column
  4113.     --   vector B resulting in a column vector.
  4114.     --   Comparability of dimensions is checked.
  4115.     -- **********************************************************************
  4116.   begin
  4117.     if A'first(2)/=B'first or A'last(2) /= B'last then
  4118.       raise INCOMPARABLE_DIMENSION;
  4119.     end if ;
  4120.     for I in A'range(1) loop
  4121.       SUM := 0.0 ;
  4122.       for K in A'range(2) loop
  4123.         SUM := SUM+A(I,K)*B(K);
  4124.       end loop;
  4125.       C(I):=SUM;
  4126.     end loop ;
  4127.     return C ;
  4128.   end "*";
  4129.  
  4130. ---
  4131.   function mat4mult (UL : MATRIX; UR : MATRIX; BL : MATRIX; BR : MATRIX;
  4132.                  B : VECTOR) return VECTOR is
  4133.     C:VECTOR(B'first..B'last);
  4134.     SUMT, SUMB : float;
  4135.     -- **********************************************************************
  4136.     --   This function performs the multiplication of a matrix A, broken into
  4137.     --  4 smaller ones due to memory limitations, and a column vector B
  4138.     --  resulting in a column vector.  Comparability of dimensions is 
  4139.     --  partially checked.
  4140.     -- **********************************************************************
  4141.   begin
  4142.     if UL'length (1) /= UR'length (1) or 
  4143.        UL'length (1) /= BL'length (1) or 
  4144.        UL'length (1) /= BR'length (1) or 
  4145.        UL'length (2) /= UR'length (2) or 
  4146.        UL'length (2) /= BL'length (2) or 
  4147.        UL'length (2) /= BR'length (2) or 
  4148.        UL'length (2) /= UL'length (1) then 
  4149.     raise INCOMPARABLE_DIMENSION; end if;
  4150.  
  4151.     if UL'first(1) /= B'first or UL'last(1) /= B'last/2 then
  4152.       raise INCOMPARABLE_DIMENSION; end if;
  4153.  
  4154.     if UL'first(2) /= B'first or 
  4155.        UL'last(2)  /= B'last/2 or
  4156.        UL'first(1) /= B'first or 
  4157.        UL'last(1)  /= B'last/2 or
  4158.        UL'last(1)  /= UL'last(2) 
  4159.     then raise INCOMPARABLE_DIMENSION;
  4160.     end if ;
  4161.  
  4162.     for I in UL'range(1) loop
  4163.     SUMT := 0.0 ;
  4164.     SUMB := 0.0 ;
  4165.       for K in UL'range(2) loop
  4166.       SUMT := SUMT+UL(I,K)*B(K) + UR(I,K) * B(k + UL'last(2));
  4167.       SUMB := SUMB+BL(I,K)*B(K) + BR(I,K) * B(k + UL'last(2));
  4168.       end loop;
  4169.       C(I):=SUMT;
  4170.       C(I + UL'last(2)):=SUMB;
  4171.     end loop ;
  4172.     return C ;
  4173.   end mat4mult;
  4174.   ---
  4175.   function "*" (A:VECTOR; B:MATRIX) return VECTOR is
  4176.     C:VECTOR(B'first(2)..B'last(2));
  4177.     SUM:float;
  4178.     -- ********************************************************************
  4179.     --   This function performs the multiplication of a row vector A and a
  4180.     --   matrix B resulting in a row vector.
  4181.     --   Comparability of dimensions is checked.
  4182.     -- ********************************************************************
  4183.   begin
  4184.     if A'first/=B'first(1) or A'last/=B'last(1) then
  4185.       raise INCOMPARABLE_DIMENSION;
  4186.     end if ;
  4187.     for J in B'range(2) loop
  4188.       SUM := 0.0 ;
  4189.       for K in A'range loop
  4190.         SUM := SUM+A(K)*B(K,J);
  4191.       end loop;
  4192.       C(J):=SUM;
  4193.     end loop ;
  4194.     return C ;
  4195.   end "*";
  4196.   ---
  4197.   function "*" (A:float; B:MATRIX) return MATRIX is
  4198.     C:MATRIX(B'first(1)..B'last(1),B'first(2)..B'last(2));
  4199.     -- ********************************************************************
  4200.     --   This function performs the scalar multipliction of a matrix B by
  4201.     --   a floating number A resulting in a matrix.
  4202.     -- ********************************************************************
  4203.   begin
  4204.     for I in B'range(1) loop
  4205.       for J in B'range(2) loop
  4206.         C(I,J) := A*B(I,J);
  4207.       end loop ;
  4208.     end loop ;
  4209.     return C ;
  4210.   end "*";
  4211.   ---
  4212.   function "*" (A:MATRIX; B:float) return MATRIX is
  4213.     C:MATRIX(A'first(1)..A'last(1),A'first(2)..A'last(2));
  4214.     -- *****************************************************************
  4215.     --   This function performs the scalar multipliction of a matrix A 
  4216.     --   by a floating number B resulting in a matrix.
  4217.     -- *****************************************************************
  4218.   begin
  4219.     return B*A ;
  4220.   end "*";
  4221.   ---
  4222.   function "*" (A:MATRIX; B:MATRIX) return MATRIX is
  4223.     C:MATRIX(A'first(1)..A'last(1),B'first(2)..B'last(2));
  4224.     SUM: float;
  4225.     -- ********************************************************************
  4226.     --   This function performs the multiplication of matrix A and matrix B
  4227.     --   resulting in a matrix. Comparability of dimensions is checked.
  4228.     -- ********************************************************************
  4229.   begin
  4230.     if A'first(2)/=B'first(1) or A'last(2)/=B'last(1) then
  4231.       raise INCOMPARABLE_DIMENSION;
  4232.     end if ;
  4233.     for I in A'range(1) loop
  4234.       for J in B'range(2) loop
  4235.         SUM := 0.0 ;
  4236.         for K in A'range(2) loop
  4237.           SUM := SUM+A(I,K)*B(K,J);
  4238.         end loop;
  4239.         C(I,J) := SUM;
  4240.       end loop ;
  4241.     end loop ;
  4242.     return C ;
  4243.   end "*";
  4244.   ---
  4245.   function "*" (A : float;  B : MATR2T) return MATR2T is
  4246.     C : MATR2T(B'first(1)..B'last(1));
  4247.     -- **********************************************************************
  4248.     --   This function performs the multiplication of each element of a
  4249.     --        MATR2T by a FLOAT resulting in a MATR2T.
  4250.     -- **********************************************************************
  4251.   begin
  4252.     for I in B'range(1) loop
  4253.  
  4254.       C(I) := A * B(I);
  4255.     end loop ;
  4256.     return C ;
  4257.   end "*";
  4258.   ---
  4259.   function "*" (A : VEC2T;  B : MATR2T) return VECTOR is
  4260.     C : VECTOR(B'first(1)..B'last(1));
  4261.     -- **********************************************************************
  4262.     --   This function performs the DOT PRODUCT of each element of a
  4263.     --        MATR2T by a VEC2T resulting in a VECTOR.
  4264.     -- **********************************************************************
  4265.   begin
  4266.     for I in B'range(1) loop
  4267.       C(I) := A * B(I);
  4268.     end loop ;
  4269.     return C ;
  4270.   end "*";
  4271.  
  4272.   ---
  4273.   function "*" (A : VECTOR;  B : MATR2T) return MATR2T is
  4274.     TEMP : MATR2T(B'range);  
  4275.     -- **********************************************************************
  4276.     --   This function multiplies each VEC2T of a MATR2T by a float from a
  4277.     --        the corresponding term of a VECTOR resulting in a MATR2T.
  4278.     -- **********************************************************************
  4279.  
  4280.   begin
  4281.     if A'first /= B'first or A'last /= B'last then 
  4282.       raise INCOMPARABLE_DIMENSION;
  4283.     end if;
  4284.     for I in  B'range loop
  4285.       TEMP(I) := A(I) * B(I);
  4286.     end loop;  
  4287.     return TEMP;
  4288.   end "*";
  4289.  
  4290.   function "**" (A : MATRIX; P : integer) return MATRIX is
  4291.     B,C : MATRIX(A'first(1)..A'last(1), A'first(1)..A'last(1));
  4292.     I_PIVOT,J_PIVOT : integer range A'first(1)..A'last(1);
  4293.     BIG_ENTRY, TEMP, EPSILON : float ;
  4294.     L, M : array(A'range(1)) of integer ;
  4295.     -- *******************************************************************
  4296.     --   This function performs the square matrix operation of " matrix A
  4297.     --   raise to integer power P ".  When  P is negative , say P = -N ,
  4298.     --   A**(-N) = (inverse(A))**N , that is, the inverse of A raise to
  4299.     --   power N .  In this case, matrix A must be non-singular.
  4300.     --   Exceptions will be raised if the matrix A is not a square matrix,
  4301.     --   or if matrix A is singular.
  4302.     -- *******************************************************************
  4303.   begin 
  4304.     if A'first(1)/=A'first(2) or A'last(1)/=A'last(2) then
  4305.       -- if not a square matrix
  4306.       raise INCOMPARABLE_DIMENSION ;
  4307.     end if;
  4308.  
  4309.     if P=0 then 
  4310.       --& B = identity matrix
  4311.  
  4312.       for I in A'range(1) loop
  4313.         for J in A'range(1) loop
  4314.           if I /= J then
  4315.             B(I,J) := 0.0;
  4316.           else
  4317.             B(I,J) := 1.0;
  4318.           end if;
  4319.         end loop;
  4320.       end loop;
  4321.       return B;
  4322.     end if ;
  4323.  
  4324.     B := A ;
  4325.  
  4326.     if P>0 then
  4327.       --& B = A multiplied itself for P times
  4328.  
  4329.       for I in 1..P-1 loop
  4330.         B := B*A ;
  4331.       end loop ;
  4332.       return B ;
  4333.     end if;
  4334.  
  4335.     -- P is negative, find inverse first
  4336.  
  4337.     -- initiate the row and column interchange information
  4338.  
  4339.     for K in B'range(1) loop
  4340.       L(K) := K ; -- row interchage information
  4341.       M(K) := K ; -- column interchange information
  4342.     end loop;
  4343.  
  4344.     -- major loop for inverse
  4345.  
  4346.     for K in B'range(1) loop
  4347.  
  4348.       -- & search for row and column index I_PIVOT, J_PIVOT 
  4349.       -- & both in (K .. B'LAST(1) ) for maximum B(I,J)
  4350.       -- & in absolute value :BIG_ENTRY
  4351.  
  4352.       BIG_ENTRY := 0.0 ;
  4353.       --
  4354.       -- check matrix singularity
  4355.       --
  4356.       for I in K..B'last(1) loop
  4357.         for J in K..B'last(1) loop
  4358.           if abs(B(I,J)) > abs(BIG_ENTRY) then
  4359.             BIG_ENTRY := B(I,J) ;
  4360.             I_PIVOT := I ;
  4361.             J_PIVOT := J ;
  4362.           end if;
  4363.         end loop;
  4364.       end loop;
  4365.       if K = B'first(1) then
  4366.         if BIG_ENTRY = 0.0 then
  4367.           raise SINGULAR;
  4368.         else
  4369.           EPSILON := float(A'length(1))*abs(BIG_ENTRY)
  4370.           *0.000001;
  4371.         end if;
  4372.       else
  4373.         if abs(BIG_ENTRY) < EPSILON then
  4374.           raise SINGULAR ;
  4375.         end if;
  4376.       end if;
  4377.  
  4378.       -- interchange row and column
  4379.  
  4380.       --& interchange K-th and I_PIVOT-th rows
  4381.       if I_PIVOT/=K then
  4382.         for J in B'range(1) loop
  4383.           TEMP := B(I_PIVOT,J);
  4384.           B(I_PIVOT,J) := B(K,J) ;
  4385.           B(K,J) := TEMP ;
  4386.         end loop;
  4387.         L(K) := I_PIVOT ;
  4388.       end if;
  4389.       --& interchange K-th and J_PIVOT-th columns
  4390.       if J_PIVOT/=K then
  4391.         for I in B'range(1) loop
  4392.           TEMP := B(I,J_PIVOT) ;
  4393.           B(I,J_PIVOT) := B(I,K) ;
  4394.           B(I,K) := TEMP ;
  4395.         end loop ;
  4396.         M(K) := J_PIVOT ;
  4397.       end if ;
  4398.  
  4399.       --& divide K-th column by minus pivot (-BIG_ENTRY)
  4400.  
  4401.       for I in B'range(1) loop
  4402.         if I/=K then
  4403.           B(I,K) := B(I,K)/(-BIG_ENTRY) ;
  4404.         end if;
  4405.       end loop ;
  4406.  
  4407.       -- reduce matrix row by row
  4408.  
  4409.       for I in B'range(1) loop
  4410.         if I/=K then
  4411.           for J in B'range(1) loop
  4412.             if J/=K then
  4413.               B(I,J):=B(I,J)+B(I,K)*B(K,J);
  4414.             end if ;
  4415.           end loop ;
  4416.         end if ;
  4417.       end loop ;  
  4418.  
  4419.       --& divide K-th row by pivot
  4420.  
  4421.       for J in B'range(1) loop
  4422.         if J/=K then
  4423.           B(K,J) := B(K,J)/BIG_ENTRY ;
  4424.         end if ;
  4425.       end loop ;
  4426.       B(K,K) := 1.0/BIG_ENTRY ;
  4427.  
  4428.     end loop ; -- end of major inverse loop
  4429.  
  4430.     -- final column and row interchange to obtain 
  4431.     -- inverse of A, i.e. A**(-1)
  4432.  
  4433.     for K in reverse B'range(1) loop
  4434.       -- column interchage
  4435.       J_PIVOT := L(K) ;
  4436.       if J_PIVOT/=K then
  4437.         --& intechange B(I,J_PIVOT) and B(I,K) for each row I
  4438.         for I in B'range(1) loop
  4439.           TEMP := B(I,J_PIVOT) ;
  4440.           B(I,J_PIVOT) := B(I,K) ;
  4441.           B(I,K) := TEMP ;
  4442.         end loop ;
  4443.       end if ;
  4444.       -- row interchage
  4445.       I_PIVOT := M(K) ;
  4446.       if I_PIVOT/=K then
  4447.         --& INTECHANGE B(I_PIVOT,J) and B(K,J) for each column J
  4448.         for J in B'range(1) loop
  4449.           TEMP := B(I_PIVOT,J) ;
  4450.           B(I_PIVOT,J) := B(K,J) ;
  4451.           B(K,J) := TEMP ;
  4452.         end loop ;
  4453.       end if ;
  4454.     end loop ;
  4455.  
  4456.     -- inverse of A is obtained and stored in B
  4457.     -- now ready to handle the negative power
  4458.  
  4459.     -- & C = B**(-P)  
  4460.     if P=-1 then
  4461.       return B ;
  4462.     end if ;
  4463.  
  4464.     C := B ;
  4465.     for I in P+1..-1 loop
  4466.       C:= C*B ;
  4467.     end loop ;
  4468.     return C;
  4469.   end "**" ;
  4470.   ---
  4471.   function "**" (A : VECTOR; B : VECTOR) return VECTOR is
  4472.     VTEMP : VECTOR (1..3);
  4473.     -- *******************************************************************
  4474.     --   This function performs the cross product of two vectors A
  4475.     --   and B resulting in a VECTOR. Usage, C := A ** B;
  4476.     --   Comparability of dimensions is checked. LIMITED TO 3D.
  4477.     -- *******************************************************************
  4478.   begin
  4479.     if A'first /= B'first or A'last /= B'last then
  4480.       raise INCOMPARABLE_DIMENSION;
  4481.     end if ;
  4482.     VTEMP(1) := A(2) * B(3) - A(3) * B(2);
  4483.     VTEMP(2) := A(3) * B(1) - A(1) * B(3);
  4484.     VTEMP(3) := A(1) * B(2) - A(2) * B(1);
  4485.     return VTEMP ;
  4486.   end "**";
  4487.   ---
  4488.   function JCROSS (A : VEC2T) return VEC2T is
  4489.     --****************************************************************************
  4490.     --    This function rotates a Vec2T 90 degrees cw.
  4491.     --****************************************************************************
  4492.     VTEMP : VEC2T;
  4493.   begin
  4494.     VTEMP := (A(2), ((-1.0) * A(1)));
  4495.     return VTEMP;
  4496.   end JCROSS;
  4497.  
  4498.   ---
  4499.   function JCROSS (A : MATR2T) return MATR2T is
  4500.     --****************************************************************************
  4501.     --    This function rotates each component Vec2T of MATR2T 90 degrees cw.
  4502.     --****************************************************************************
  4503.     B : MATR2T(A'first(1)..A'last(1));
  4504.   begin
  4505.     for I in A'range loop
  4506.       B(I) := JCROSS(A(I));
  4507.     end loop;
  4508.     return     B;
  4509.   end JCROSS;
  4510.  
  4511.   ---
  4512.   function ROTX (A : VEC2T) return VEC2T is
  4513.     --****************************************************************************
  4514.     --    This function rotates a Vec2T 180 degrees about the X axis.
  4515.     --****************************************************************************
  4516.   begin
  4517.     return (A(1), -A(2)); 
  4518.   end ROTX;
  4519.  
  4520.   ---
  4521.   function ROTY (A : VEC2T) return VEC2T is
  4522.     --************************************************************************
  4523.     --    This function rotates a Vec2T 180 degrees about the Y axis.
  4524.     --************************************************************************
  4525.   begin
  4526.     return (-A(1), A(2)); 
  4527.   end ROTY;
  4528.   ---
  4529.   function aXbDOTj(A : VEC2T; B : VEC2T) return FLOAT is
  4530.     --************************************************************************
  4531.     --Gets magnitude of A cross B for 2 2D vectors.
  4532.     --************************************************************************
  4533.   temp : float;
  4534.   begin
  4535.   temp := A(2) * B(1) - A(1) * B(2);
  4536.   return temp;
  4537.   end aXbDOTj;
  4538.   ---
  4539.   function GETTAN (A : VEC2T; B : VEC2T) return FLOAT is
  4540.     --************************************************************************
  4541.     --Gets TAN(THETA) where THETA is CW angle between 2 2D vectors.
  4542.     --************************************************************************
  4543. epsilon, num, denom : float := 0.00000001;
  4544.  
  4545.   begin
  4546. denom := A * B;
  4547. num :=  aXbDOTj(A,B);
  4548.  
  4549. if denom < epsilon and denom >= 0.0  then
  4550.      put_line("Tangent is beyond the limit val of");
  4551.      return (num / epsilon);
  4552.  
  4553. elsif denom > -epsilon and denom < 0.0  then
  4554.      put_line("Tangent is beyond the limit val of");
  4555.    return ((-num) / epsilon);
  4556. else
  4557. return  aXbDOTj(A,B)/(A * B);
  4558. end if;
  4559. end gettan;
  4560. end MATRIX_PACKAGE;
  4561.  
  4562.  
  4563.  
  4564.  
  4565.  
  4566.  
  4567.  
  4568. --::::::::::
  4569. --mlib.bdy
  4570. --::::::::::
  4571. package body FLOATING_CHARACTERISTICS is
  4572. --  This package is a floating mantissa definition of a binary FLOAT
  4573.  
  4574.     A, B, Y, Z : FLOAT;
  4575.     I, K, MX, IZ : INTEGER;
  4576.     BETA, BETAM1, BETAIN : FLOAT;
  4577.     ONE : FLOAT := 1.0;
  4578.     ZERO : FLOAT := 0.0;
  4579.  
  4580.   procedure DEFLOAT(X : in FLOAT;
  4581.                     L : out EXPONENT_TYPE; E : out MANTISSA_TYPE) is
  4582. --  This is admittedly a slow method - but portable - for breaking down
  4583. --  a floating point number into its exponent and mantissa
  4584. --  Obviously with knowledge of the machine representation
  4585. --  it could be replaced with a couple of simple extractions
  4586.     EXPONENT_LENGTH : INTEGER := IEXP;
  4587.     M, N : EXPONENT_TYPE;
  4588.     W, Y, Z : FLOAT;
  4589.     F : MANTISSA_TYPE;
  4590.   begin
  4591.     N := 0;
  4592.     F := 0.0;
  4593.     Y := ABS(X);
  4594.     if Y = 0.0  then
  4595.       return;
  4596.     elsif Y < 0.5  then
  4597.       for J in reverse 0..(EXPONENT_LENGTH - 2)  loop
  4598.       --  Dont want to go all the way to 2.0**(EXPONENT_LENGTH - 1)
  4599.       --  Since that (or its reciprocal) will overflow if exponent biased
  4600.       --  Ought to use talbular values rather than compute each time
  4601.         M := EXPONENT_TYPE(2 ** J);
  4602.         Z := 1.0 / (2.0**M);
  4603.         W := Y / Z;
  4604.         if W < 1.0  then
  4605.           Y := W;
  4606.           N := N - M;
  4607.         end if;
  4608.       end loop;
  4609.     else
  4610.       for J in reverse 0..(EXPONENT_LENGTH - 2)  loop
  4611.         M := EXPONENT_TYPE(2 ** J);
  4612.         Z := 2.0**M;
  4613.         W := Y / Z;
  4614.         if W >= 0.5  then
  4615.           Y := W;
  4616.           N := N + M;
  4617.         end if;
  4618.       end loop;
  4619.     --  And just to clear up any loose ends from biased exponents
  4620.     end if;
  4621.     while Y < 0.5  loop
  4622.       Y := Y * 2.0;
  4623.       N := N - 1;
  4624.     end loop;
  4625.     while Y >= 1.0  loop
  4626.       Y := Y / 2.0;
  4627.       N := N + 1;
  4628.     end loop;
  4629.     F := MANTISSA_TYPE(Y);
  4630.     if X < 0.0  then
  4631.       F := -F;
  4632.     end if;
  4633.     L := N;
  4634.     E := F; 
  4635.     return;
  4636.   exception
  4637.   when others =>
  4638.     L := 0;
  4639.     E := 0.0;
  4640.     return;
  4641.   end DEFLOAT;
  4642.  
  4643.  
  4644.   procedure REFLOAT(N : in EXPONENT_TYPE; F : in MANTISSA_TYPE; 
  4645.                                                    Z : out FLOAT) is
  4646. --  Again a brute force method - but portable
  4647. --  Watch out near MAXEXP
  4648.     M : INTEGER;
  4649.     X, Y : FLOAT;
  4650.   begin
  4651.     if F = 0.0  then
  4652.       X := ZERO;
  4653.       return;
  4654.     end if;
  4655.     M := INTEGER(N);
  4656.     Y := ABS(FLOAT(F));
  4657.     while Y < 0.5  loop
  4658.       M := M - 1;
  4659.       if M < MINEXP  then
  4660.         X := ZERO;
  4661.       end if;
  4662.       Y := Y + Y;
  4663.       exit when M <= MINEXP;
  4664.     end loop;
  4665.     if M = MAXEXP  then
  4666.       M := M - 1;
  4667.       X := Y * 2.0**M;
  4668.       X := X * 2.0;
  4669.     elsif M <= MINEXP + 2  then
  4670.       M := M + 3;
  4671.       X := Y * 2.0**M;
  4672.       X := ((X / 2.0) / 2.0) / 2.0;
  4673.     else
  4674.       X := Y * 2.0**M;
  4675.     end if;
  4676.     if F < 0.0  then
  4677.       X := -X;
  4678.     end if;
  4679.     Z := X;
  4680.     return;
  4681.   end REFLOAT;
  4682.  
  4683.   function CONVERT_TO_FLOAT(K : INTEGER) return FLOAT is
  4684.   begin
  4685.     return FLOAT(K);
  4686.   end CONVERT_TO_FLOAT;
  4687.  
  4688.   --function CONVERT_TO_FLOAT(N : EXPONENT_TYPE) return FLOAT is
  4689.   --begin
  4690.     --return FLOAT(N);
  4691.  --end CONVERT_TO_FLOAT;
  4692.  
  4693.   function CONVERT_TO_FLOAT(F : MANTISSA_TYPE) return FLOAT is
  4694.   begin
  4695.     return FLOAT(F);
  4696.   end CONVERT_TO_FLOAT;
  4697.  
  4698.  
  4699. begin
  4700. --  Initialization for the VAX with values derived by MACHAR
  4701. --  In place of running MACHAR as the actual initialization
  4702.  
  4703.     IBETA :=    2;
  4704.     IT :=    24;
  4705.     IRND :=    1;
  4706.     NEGEP :=    -24;
  4707.     EPSNEG :=    5.9604644E-008;
  4708.     MACHEP :=    -24;
  4709.     EPS :=    5.9604644E-008;
  4710.     NGRD :=    0;
  4711.     XMIN := 5.9E-39;
  4712.     MINEXP :=    -126;
  4713.     IEXP :=    8;
  4714.     MAXEXP :=    127;
  4715.     XMAX :=    8.5E37 * 2.0;
  4716.  
  4717.  
  4718. ----  This initialization is the MACHAR routine of Cody and Waite Appendix B.
  4719. --PUT("INITIALIZATING WITH MACHAR     -     ");
  4720. --    A := ONE;
  4721. --    while (((A + ONE) - A) - ONE) = ZERO  loop
  4722. --      A := A + A;
  4723. --    end loop;
  4724. --    B := ONE;
  4725. --    while ((A + B) - A) = ZERO  loop
  4726. --      B := B + B;
  4727. --    end loop;
  4728. --    IBETA := INTEGER((A + B) - A);
  4729. --    BETA := CONVERT_TO_FLOAT(IBETA);
  4730. --
  4731. --
  4732. --    IT := 0;
  4733. --    B := ONE;
  4734. --    while (((B + ONE) - B) - ONE) = ZERO  loop
  4735. --      IT := IT + 1;
  4736. --      B := B * BETA;
  4737. --    end loop;
  4738. --
  4739. --
  4740. --    IRND := 0;
  4741. --    BETAM1 := BETA - ONE;
  4742. --    if ((A + BETAM1) - A) /= ZERO  then
  4743. --      IRND := 1;
  4744. --    end if;
  4745. --
  4746. --
  4747. --    NEGEP := IT + 3;
  4748. --    BETAIN := ONE / BETA;
  4749. --    A := ONE;
  4750. --  --  for I in 1..NEGEP  loop
  4751. --  for I in 1..50  loop
  4752. --  exit when I > NEGEP;
  4753. --      A := A * BETAIN;
  4754. --    end loop;
  4755. --    B := A;
  4756. --    while ((ONE - A) - ONE) = ZERO  loop
  4757. --      A := A * BETA;
  4758. --      NEGEP := NEGEP - 1;
  4759. --    end loop;
  4760. --    NEGEP := -NEGEP;
  4761. --
  4762. --
  4763. --    EPSNEG := A;
  4764. --    if (IBETA /= 2) and (IRND /= 0)  then
  4765. --      A := (A * (ONE + A)) / (ONE + ONE);
  4766. --      if ((ONE - A) - ONE) /= ZERO  then
  4767. --        EPSNEG := A;
  4768. --      end if;
  4769. --    end if;
  4770. --
  4771. --
  4772. --    MACHEP := -IT - 3;
  4773. --    A := B;
  4774. --    while ((ONE + A) - ONE) = ZERO  loop
  4775. --      A := A * BETA;
  4776. --      MACHEP := MACHEP + 1;
  4777. --    end loop;
  4778. --
  4779. --
  4780. --    EPS := A;
  4781. --    if (IBETA /= 2) and (IRND /= 0)  then
  4782. --      A := (A * (ONE + A)) / (ONE + ONE);
  4783. --      if ((ONE + A) - ONE) /= ZERO  then
  4784. --        EPS := A;
  4785. --      end if;
  4786. --    end if;
  4787. --
  4788. --
  4789. --    NGRD := 0;
  4790. --    if ((IRND = 0) and ((ONE + EPS) * ONE - ONE) /= ZERO)  then
  4791. --      NGRD := 1;
  4792. --    end if;
  4793. --
  4794. --
  4795. --    I := 0;
  4796. --    K := 1;
  4797. --    Z := BETAIN;
  4798. --    loop
  4799. --      Y := Z;
  4800. --      Z := Y * Y;
  4801. --      A := Z * ONE;
  4802. --      exit when ((A + A) = ZERO) or (ABS(Z) >= Y);
  4803. --      I := I + 1;
  4804. --      K := K + K;
  4805. --    end loop;
  4806. --    if (IBETA /= 10)  then
  4807. --      IEXP := I + 1;
  4808. --      MX := K + K;
  4809. --    else
  4810. --      IEXP := 2;
  4811. --      IZ := IBETA;
  4812. --      while (K >= IZ)  loop
  4813. --        IZ := IZ * IBETA;
  4814. --        IEXP := IEXP + 1;
  4815. --      end loop;
  4816. --      MX := IZ + IZ - 1;
  4817. --    end if;
  4818. --
  4819. --    loop
  4820. --      XMIN := Y;
  4821. --      Y := Y * BETAIN;
  4822. --      A := Y * ONE;
  4823. --      exit when ((A + A) = ZERO) or (ABS(Y) >= XMIN);
  4824. --      K := K + 1;
  4825. --    end loop;
  4826. --
  4827. --
  4828. --    MINEXP := -K;
  4829. --
  4830. --
  4831. --    if ((MX <= (K + K - 3)) and (IBETA /= 10))  then
  4832. --      MX := MX + MX;
  4833. --      IEXP := IEXP + 1;
  4834. --    end if;
  4835. --
  4836. --
  4837. --    MAXEXP := MX + MINEXP;
  4838. --    I := MAXEXP + MINEXP;
  4839. --    if ((IBETA = 2) and (I = 0))  then
  4840. --      MAXEXP := MAXEXP - 1;
  4841. --    end if;
  4842. --    if (I > 20)  then
  4843. --      MAXEXP := MAXEXP - 1;
  4844. --    end if;
  4845. --    if (A /= Y)  then
  4846. --      MAXEXP := MAXEXP - 2;
  4847. --    end if;
  4848. --
  4849. --
  4850. --    XMAX := ONE - EPSNEG;
  4851. --    if ((XMAX * ONE) /= XMAX)  then
  4852. --      XMAX := ONE - BETA * EPSNEG;
  4853. --    end if;
  4854. --    XMAX := XMAX / (BETA * BETA * BETA * XMIN);
  4855. --    I := MAXEXP + MINEXP + 3;
  4856. --    if I > 0  then
  4857. --      for J in 1..50  loop
  4858. --  exit when J > I;
  4859. --        if IBETA = 2  then
  4860. --          XMAX := XMAX + XMAX;
  4861. --        else
  4862. --          XMAX := XMAX * BETA;
  4863. --        end if;
  4864. --      end loop;
  4865. --    end if;
  4866. --
  4867. --PUT("INITIALIZED"); NEW_LINE;
  4868.  
  4869. end FLOATING_CHARACTERISTICS;
  4870.  
  4871. with FLOATING_CHARACTERISTICS;
  4872. use FLOATING_CHARACTERISTICS;
  4873. package body NUMERIC_PRIMITIVES is
  4874.  
  4875.  
  4876.   function SIGN(X, Y : FLOAT) return FLOAT is
  4877.     --  Returns the value of X with the sign of Y
  4878.   begin
  4879.     if Y >= 0.0  then
  4880.       return X;
  4881.     else
  4882.       return -X;
  4883.     end if;
  4884.   end SIGN;
  4885.  
  4886.   function MAX(X, Y : FLOAT) return FLOAT is
  4887.   begin
  4888.     if X >= Y  then
  4889.       return X;
  4890.     else
  4891.       return Y;
  4892.     end if;
  4893.   end MAX;
  4894.  
  4895.   function TRUNCATE(X : FLOAT) return FLOAT is
  4896.   --  Optimum code depends on how the system rounds at exact halves
  4897.   begin
  4898.     if FLOAT(INTEGER(X)) = X  then
  4899.       return X;
  4900.     end if;
  4901.     if X > ZERO  then
  4902.       return FLOAT(INTEGER(X - HALF));
  4903.     elsif X = ZERO  then
  4904.       return ZERO;
  4905.     else
  4906.       return FLOAT(INTEGER(X + HALF));
  4907.     end if;
  4908.   end TRUNCATE;
  4909.  
  4910.   function ROUND(X : FLOAT) return FLOAT is
  4911.   begin
  4912.     return FLOAT(INTEGER(X));
  4913.   end ROUND;
  4914.  
  4915.  
  4916.   package KEY is
  4917.     X : INTEGER := 10_001;
  4918.     Y : INTEGER := 20_001;
  4919.     Z : INTEGER := 30_001;
  4920.   end KEY;
  4921.  
  4922.   function RAN return FLOAT is
  4923.   --  This rectangular random number routine is adapted from a report
  4924.   --  "A Pseudo-Random Number Generator" by B. A. Wichmann and I. D. Hill
  4925.   --  NPL Report DNACS XX (to be published)
  4926.   --  In this stripped version, it is suitable for machines supporting 
  4927.   --  INTEGER at only 16 bits and is portable in Ada
  4928.     W : FLOAT;
  4929.   begin
  4930.  
  4931.     KEY.X := 171 * (KEY.X mod 177 - 177) -  2 * (KEY.X / 177);
  4932.     if KEY.X < 0  then
  4933.       KEY.X := KEY.X + 30269;
  4934.     end if;
  4935.  
  4936.     KEY.Y := 172 * (KEY.Y mod 176 - 176) - 35 * (KEY.Y / 176);
  4937.     if KEY.Y < 0  then
  4938.       KEY.Y := KEY.Y + 30307;
  4939.     end if;
  4940.  
  4941.     KEY.Z := 170 * (KEY.Z mod 178 - 178) - 63 * (KEY.Z / 178);
  4942.     if KEY.Z < 0  then
  4943.       KEY.Z := KEY.Z + 30323;
  4944.     end if;
  4945.  
  4946.     --  CONVERT_TO_FLOAT is used instead of FLOAT since the floating
  4947.     --  type may be software defined
  4948.  
  4949.     W :=     CONVERT_TO_FLOAT(KEY.X)/30269.0
  4950.            + CONVERT_TO_FLOAT(KEY.Y)/30307.0
  4951.            + CONVERT_TO_FLOAT(KEY.Z)/30323.0;
  4952.  
  4953.     return  W - CONVERT_TO_FLOAT(INTEGER(W - 0.5));
  4954.  
  4955.   end RAN;
  4956.  
  4957.  
  4958. begin
  4959.  
  4960.   ZERO  := CONVERT_TO_FLOAT(INTEGER(0));
  4961.   ONE   := CONVERT_TO_FLOAT(INTEGER(1));
  4962.   TWO   := ONE + ONE;
  4963.   THREE := ONE + ONE + ONE;
  4964.   HALF  := ONE / TWO;
  4965.  
  4966.   PI            := CONVERT_TO_FLOAT(INTEGER(3)) +
  4967.                    CONVERT_TO_FLOAT(MANTISSA_TYPE(0.14159_26535_89793_23846));
  4968.   ONE_OVER_PI   := CONVERT_TO_FLOAT(MANTISSA_TYPE(0.31830_98861_83790_67154));
  4969.   TWO_OVER_PI   := CONVERT_TO_FLOAT(MANTISSA_TYPE(0.63661_97723_67581_34308));
  4970.   PI_OVER_TWO   := CONVERT_TO_FLOAT(INTEGER(1)) +
  4971.                    CONVERT_TO_FLOAT(MANTISSA_TYPE(0.57079_63267_94896_61923));
  4972.   PI_OVER_THREE := CONVERT_TO_FLOAT(INTEGER(1)) +
  4973.                    CONVERT_TO_FLOAT(MANTISSA_TYPE(0.04719_75511_96597_74615));
  4974.   PI_OVER_FOUR  := CONVERT_TO_FLOAT(MANTISSA_TYPE(0.78539_81633_97448_30962));
  4975.   PI_OVER_SIX   := CONVERT_TO_FLOAT(MANTISSA_TYPE(0.52359_87755_98298_87308));
  4976.  
  4977. end NUMERIC_PRIMITIVES;
  4978.  
  4979. with TEXT_IO;
  4980. with FLOATING_CHARACTERISTICS;
  4981. with NUMERIC_PRIMITIVES;
  4982. package body CORE_FUNCTIONS is
  4983.   use TEXT_IO;
  4984.   use FLOATING_CHARACTERISTICS;
  4985.   use NUMERIC_PRIMITIVES;
  4986.   package FLT_IO is new FLOAT_IO(FLOAT);
  4987.   use FLT_IO;
  4988.  
  4989. --  The following routines are coded directly from the algorithms and
  4990. --  coeficients given in "Software Manual for the Elementry Functions"
  4991. --  by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980
  4992. --  CBRT by analogy
  4993. --  A more general formulation uses MANTISSA_TYPE, etc.
  4994. --  The coeficients are appropriate for 25 to 32 bits floating significance
  4995. --  They will work for less but slightly shorter versions are possible
  4996. --  The routines are coded to stand alone so they need not be compiled together
  4997.  
  4998. --  These routines have been coded to accept a general MANTISSA_TYPE
  4999. --  That is, they are designed to work with a manitssa either fixed of float
  5000. --  There are some explicit conversions which are required but these will
  5001. --  not cause any extra code to be generated
  5002.  
  5003. --      16 JULY 1982       W A WHITAKER  AFATL EGLIN AFB FL 32542
  5004. --                         T C EICHOLTZ  USAFA
  5005.  
  5006.  
  5007.   function SQRT(X : FLOAT) return FLOAT is
  5008.     M, N : EXPONENT_TYPE;
  5009.     F, Y : MANTISSA_TYPE;
  5010.     RESULT : FLOAT;
  5011.  
  5012.     subtype INDEX is INTEGER range 0..100;    --  #########################
  5013.     SQRT_L1 : INDEX := 3;
  5014.     --  Could get away with SQRT_L1 := 2 for 28 bits
  5015.     --  Using the better Cody-Waite coeficients overflows MANTISSA_TYPE
  5016.     SQRT_C1 : MANTISSA_TYPE := 8#0.3317777777#;
  5017.     SQRT_C2 : MANTISSA_TYPE := 8#0.4460000000#;
  5018.     SQRT_C3 : MANTISSA_TYPE := 8#0.55202_36314_77747_36311_0#;
  5019.  
  5020.   begin
  5021.     if X = ZERO  then
  5022.       RESULT := ZERO;
  5023.       return RESULT;
  5024.     elsif X = ONE  then            --  To get exact SQRT(1.0)
  5025.       RESULT := ONE;
  5026.       return RESULT;
  5027.     elsif X < ZERO  then
  5028.       NEW_LINE;
  5029.       PUT("CALLED SQRT FOR NEGATIVE ARGUMENT   ");
  5030.       PUT(X);
  5031.       PUT("   USED ABSOLUTE VALUE");
  5032.       NEW_LINE;
  5033.       RESULT := SQRT(ABS(X));
  5034.       return RESULT;
  5035.     else
  5036.       DEFLOAT(X, N, F);
  5037.       Y := SQRT_C1 + MANTISSA_TYPE(SQRT_C2 * F);
  5038.       for J in 1..SQRT_L1  loop
  5039.         Y := Y/MANTISSA_DIVISOR_2 + MANTISSA_TYPE((F/MANTISSA_DIVISOR_2)/Y);
  5040.       end loop;
  5041.       if (N mod 2) /= 0  then
  5042.         Y := MANTISSA_TYPE(SQRT_C3 * Y);
  5043.         N := N + 1;
  5044.       end if;
  5045.       M := N/2;
  5046.       REFLOAT(M,Y,RESULT);
  5047.       return RESULT;
  5048.     end if;
  5049.   exception
  5050.   when others =>
  5051.     NEW_LINE; PUT(" EXCEPTION IN SQRT, X = "); PUT(X);
  5052.     PUT("  RETURNED 1.0"); NEW_LINE;
  5053.     return ONE;
  5054.   end SQRT;
  5055.  
  5056.  
  5057.   function CBRT(X : FLOAT) return FLOAT is
  5058.     M, N : EXPONENT_TYPE;
  5059.     F, Y : MANTISSA_TYPE;
  5060.     RESULT : FLOAT;
  5061.  
  5062.     subtype INDEX is INTEGER range 0..100;    --  #########################
  5063.     CBRT_L1 : INDEX := 3;
  5064.     CBRT_C1 : MANTISSA_TYPE := 0.5874009;
  5065.     CBRT_C2 : MANTISSA_TYPE := 0.4125990;
  5066.     CBRT_C3 : MANTISSA_TYPE := 0.62996_05249;
  5067.     CBRT_C4 : MANTISSA_TYPE := 0.79370_05260;
  5068.  
  5069.   begin
  5070.     if X = ZERO then
  5071.       RESULT := ZERO;
  5072.       return RESULT;
  5073.     else
  5074.       DEFLOAT(X, N, F);
  5075.       F := ABS(F);
  5076.       Y := CBRT_C1 + MANTISSA_TYPE(CBRT_C2 * F);
  5077.       for J in 1 .. CBRT_L1 loop
  5078.         Y :=     Y
  5079.             - (  Y/MANTISSA_DIVISOR_3 
  5080.                - MANTISSA_TYPE((F/MANTISSA_DIVISOR_3) / MANTISSA_TYPE(Y*Y)) );
  5081.       end loop;
  5082.       case (N mod 3) is
  5083.         when 0 =>
  5084.           null;
  5085.         when 1 =>
  5086.           Y := MANTISSA_TYPE(CBRT_C3 * Y);
  5087.           N := N + 2;
  5088.         when 2 =>
  5089.           Y := MANTISSA_TYPE(CBRT_C4 * Y);
  5090.           N := N + 1;
  5091.         when others =>
  5092.           null;
  5093.       end case;
  5094.       M := N/3;
  5095.       if X < ZERO  then
  5096.         Y := -Y;
  5097.       end if;
  5098.       REFLOAT(M, Y, RESULT);
  5099.       return RESULT;
  5100.     end if;
  5101.   exception
  5102.     when others =>
  5103.       RESULT := ONE;
  5104.       if X < ZERO then
  5105.       RESULT := - ONE;
  5106.       end if;
  5107.       NEW_LINE; PUT("EXCEPTION IN CBRT, X = "); PUT(X);
  5108.       PUT("  RETURNED  "); PUT(RESULT); NEW_LINE;
  5109.       return RESULT;
  5110.   end CBRT;
  5111.  
  5112.     function LOG(X : FLOAT) return FLOAT is
  5113.   --  Uses fixed formulation for generality
  5114.  
  5115.     RESULT : FLOAT;
  5116.     N : EXPONENT_TYPE;
  5117.     XN : FLOAT;
  5118.     Y : FLOAT;
  5119.     F : MANTISSA_TYPE;
  5120.     Z, ZDEN, ZNUM : MANTISSA_TYPE;
  5121.  
  5122.     C0 : constant MANTISSA_TYPE := 0.20710_67811_86547_52440;
  5123.                                                --  SQRT(0.5) - 0.5
  5124.     C1 : constant FLOAT := 8#0.543#;
  5125.     C2 : constant FLOAT :=-2.12194_44005_46905_82767_9E-4;
  5126.  
  5127.     function R(Z : MANTISSA_TYPE) return MANTISSA_TYPE is
  5128.     --  Use fixed formulation here because the float coeficents are > 1.0
  5129.     --  and would exceed the limits on a MANTISSA_TYPE
  5130.       A0 : constant MANTISSA_TYPE := 0.04862_85276_587;
  5131.       B0 : constant MANTISSA_TYPE := 0.69735_92187_803;
  5132.       B1 : constant MANTISSA_TYPE :=-0.125;
  5133.       C  : constant MANTISSA_TYPE := 0.01360_09546_862;
  5134.     begin
  5135.       return Z + MANTISSA_TYPE(Z * 
  5136.           MANTISSA_TYPE(MANTISSA_TYPE(Z * Z) * (C +
  5137.           MANTISSA_TYPE(A0/(B0 + MANTISSA_TYPE(B1 * MANTISSA_TYPE(Z * Z)))))));
  5138.     end R;
  5139.  
  5140.   begin
  5141.  
  5142.     if X < ZERO      then
  5143.       NEW_LINE;
  5144.       PUT("CALLED LOG FOR NEGATIVE ");
  5145.       PUT(X);
  5146.       PUT("   USE ABS => ");
  5147.       RESULT := LOG(ABS(X));
  5148.       PUT(RESULT);
  5149.       NEW_LINE;
  5150.     elsif X = ZERO  then
  5151.       NEW_LINE;
  5152.       PUT("CALLED LOG FOR ZERO ARGUMENT, RETURNED ");
  5153.       RESULT := -XMAX;      --  SUPPOSED TO BE -LARGE
  5154.       PUT(RESULT);
  5155.       NEW_LINE;
  5156.     else
  5157.       DEFLOAT(X,N,F);
  5158.       ZNUM := F - MANTISSA_HALF;
  5159.       Y := CONVERT_TO_FLOAT(ZNUM);
  5160.       ZDEN := ZNUM / MANTISSA_DIVISOR_2 + MANTISSA_HALF;
  5161.       if ZNUM > C0  then
  5162.         Y := Y - MANTISSA_HALF;
  5163.         ZNUM := ZNUM - MANTISSA_HALF;
  5164.         ZDEN := ZDEN + MANTISSA_HALF/MANTISSA_DIVISOR_2;
  5165.       else
  5166.         N := N -1;
  5167.       end if;
  5168.       Z    := MANTISSA_TYPE(ZNUM / ZDEN);
  5169.       RESULT := CONVERT_TO_FLOAT(R(Z));
  5170.       if N /= 0  then
  5171.         XN := CONVERT_TO_FLOAT(N);
  5172.         RESULT := (XN * C2 + RESULT) + XN * C1;
  5173.       end if;
  5174.     end if;
  5175.     return RESULT;
  5176.  
  5177.   exception
  5178.   when others =>
  5179.     NEW_LINE; PUT(" EXCEPTION IN LOG, X = "); PUT(X);
  5180.     PUT("  RETURNED 0.0"); NEW_LINE;
  5181.     return ZERO;
  5182.   end LOG;
  5183.  
  5184.  
  5185.   function LOG10(X : FLOAT) return FLOAT is
  5186.     LOG_10_OF_2 : constant FLOAT :=
  5187.              CONVERT_TO_FLOAT(MANTISSA_TYPE(8#0.33626_75425_11562_41615#));
  5188.   begin
  5189.     return LOG(X) * LOG_10_OF_2;
  5190.   end LOG10;
  5191.  
  5192.   function EXP(X : FLOAT) return FLOAT is
  5193.  
  5194.     RESULT : FLOAT;
  5195.     N : EXPONENT_TYPE;
  5196.     XG, XN, X1, X2 : FLOAT;
  5197.     F, G : MANTISSA_TYPE;
  5198.  
  5199.     BIGX : FLOAT := EXP_LARGE;
  5200.     SMALLX : FLOAT := EXP_SMALL;
  5201.  
  5202.     ONE_OVER_LOG_2 : constant FLOAT :=  1.4426_95040_88896_34074;
  5203.     C1 : constant FLOAT :=  0.69335_9375;
  5204.     C2 : constant FLOAT := -2.1219_44400_54690_58277E-4;
  5205.  
  5206.     function R(G : MANTISSA_TYPE) return MANTISSA_TYPE is
  5207.       Z , GP, Q : MANTISSA_TYPE;
  5208.  
  5209.       P0 : constant MANTISSA_TYPE :=  0.24999_99999_9992;
  5210.       P1 : constant MANTISSA_TYPE :=  0.00595_04254_9776;
  5211.       Q0 : constant MANTISSA_TYPE :=  0.5;
  5212.       Q1 : constant MANTISSA_TYPE :=  0.05356_75176_4522;
  5213.       Q2 : constant MANTISSA_TYPE :=  0.00029_72936_3682;
  5214.     begin
  5215.       Z  := MANTISSA_TYPE(G * G);
  5216.       GP := MANTISSA_TYPE( (MANTISSA_TYPE(P1 * Z) + P0) * G );
  5217.       Q  := MANTISSA_TYPE( (MANTISSA_TYPE(Q2 * Z) + Q1) * Z ) + Q0;
  5218.       return MANTISSA_HALF + MANTISSA_TYPE( GP /(Q - GP) );
  5219.     end R;
  5220.  
  5221.  
  5222.   begin
  5223.  
  5224.     if X > BIGX  then
  5225.       NEW_LINE;
  5226.       PUT("  EXP CALLED WITH TOO BIG A POSITIVE ARGUMENT, ");
  5227.           PUT(X); PUT("   RETURNED XMAX");
  5228.       NEW_LINE;
  5229.       RESULT := XMAX;
  5230.     elsif X < SMALLX  then
  5231.       NEW_LINE;
  5232.       PUT("  EXP CALLED WITH TOO BIG A NEGATIVE ARGUMENT,  ");
  5233.           PUT(X); PUT("    RETURNED ZERO");
  5234.       NEW_LINE;
  5235.       RESULT := ZERO;
  5236.     elsif ABS(X) < EPS  then
  5237.       RESULT := ONE;
  5238.     else
  5239.       N  := EXPONENT_TYPE(X * ONE_OVER_LOG_2);
  5240.       XN := CONVERT_TO_FLOAT(N);
  5241.       X1 := ROUND(X);
  5242.       X2 := X - X1;
  5243.       XG := ( (X1 - XN * C1) + X2 ) - XN * C2;
  5244.       G  := MANTISSA_TYPE(XG);
  5245.       N  := N + 1;
  5246.       F := R(G);
  5247.       REFLOAT(N, F, RESULT);
  5248.     end if;
  5249.     return RESULT;
  5250.  
  5251.   exception
  5252.   when others =>
  5253.     NEW_LINE; PUT(" EXCEPTION IN EXP, X = "); PUT(X);
  5254.     PUT("  RETURNED 1.0"); NEW_LINE;
  5255.     return ONE;
  5256.   end EXP;
  5257.  
  5258. function "**" (X, Y : FLOAT) return FLOAT is
  5259. --  This is the last function to be coded since it appeared that it really
  5260. --  was un-Ada-like and ought not be in the regular package
  5261. --  Nevertheless it was included in this version
  5262. --  It is specific for FLOAT and does not have the MANTISSA_TYPE generality
  5263.   M, N : EXPONENT_TYPE;
  5264.   G : MANTISSA_TYPE;
  5265.   P, TEMP, IW1, I : INTEGER;
  5266.   RESULT, Z, V, R, U1, U2, W, W1, W2, W3, Y1, Y2 : FLOAT;
  5267.  
  5268.   K : constant FLOAT := 0.44269_50408_88963_40736;
  5269.   IBIGX : constant INTEGER := INTEGER(TRUNCATE(16.0 * LOG(XMAX) - 1.0));
  5270.   ISMALLX : constant INTEGER := INTEGER(TRUNCATE(16.0 * LOG(XMIN) + 1.0));
  5271.  
  5272.   P1 : constant FLOAT := 0.83333_32862_45E-1;
  5273.   P2 : constant FLOAT := 0.12506_48500_52E-1;
  5274.  
  5275.   Q1 : constant FLOAT := 0.69314_71805_56341;
  5276.   Q2 : constant FLOAT := 0.24022_65061_44710;
  5277.   Q3 : constant FLOAT := 0.55504_04881_30765E-1;
  5278.   Q4 : constant FLOAT := 0.96162_06595_83789E-2;
  5279.   Q5 : constant FLOAT := 0.13052_55159_42810E-2;
  5280.  
  5281.   A1 : array (1 .. 17) of FLOAT:=
  5282.      (  8#1.00000_0000#,        
  5283.         8#0.75222_5750#,        
  5284.         8#0.72540_3067#,        
  5285.         8#0.70146_3367#,        
  5286.         8#0.65642_3746#,        
  5287.         8#0.63422_2140#,        
  5288.         8#0.61263_4520#,        
  5289.         8#0.57204_2434#,        
  5290.         8#0.55202_3631#,        
  5291.         8#0.53254_0767#,        
  5292.         8#0.51377_3265#,        
  5293.         8#0.47572_4623#,        
  5294.         8#0.46033_7602#,        
  5295.         8#0.44341_7233#,        
  5296.         8#0.42712_7017#,        
  5297.         8#0.41325_3033#,        
  5298.         8#0.40000_0000#  );        
  5299.                 
  5300.   A2 : array (1 .. 8) of FLOAT :=
  5301.      (  8#0.00000_00005_22220_66302_61734_72062#,
  5302.         8#0.00000_00003_02522_47021_04062_61124#,
  5303.         8#0.00000_00005_21760_44016_17421_53016#,
  5304.         8#0.00000_00007_65401_41553_72504_02177#,
  5305.         8#0.00000_00002_44124_12254_31114_01243#,
  5306.         8#0.00000_00000_11064_10432_66404_42174#,
  5307.         8#0.00000_00004_72542_16063_30176_55544#,
  5308.         8#0.00000_00001_74611_03661_23056_22556#  );
  5309.        
  5310.  
  5311.   function REDUCE (V : FLOAT) return FLOAT is
  5312.   begin
  5313.     return FLOAT(INTEGER(16.0 * V)) * 0.0625;
  5314.   end REDUCE;
  5315.  
  5316.   begin
  5317.     if X <= ZERO then
  5318.       if X < ZERO then
  5319.         RESULT := (ABS(X))**Y;
  5320.         NEW_LINE;
  5321.         PUT("X**Y CALLED WITH X = "); PUT(X); NEW_LINE;
  5322.         PUT("USED ABS, RETURNED "); PUT(RESULT); NEW_LINE;
  5323.       else
  5324.         if Y <= ZERO then
  5325.           if Y = ZERO then
  5326.             RESULT := ZERO;
  5327.           else
  5328.             RESULT := XMAX;
  5329.           end if;
  5330.           NEW_LINE;
  5331.           PUT("X**Y CALLED WITH X = 0, Y = "); PUT(Y); NEW_LINE;
  5332.           PUT("RETURNED "); PUT(RESULT); NEW_LINE;
  5333.         else
  5334.           RESULT := ZERO;
  5335.         end if;
  5336.       end if;
  5337.     else
  5338.       DEFLOAT(X, M, G);
  5339.       P := 1;
  5340.       if G <= A1(9) then
  5341.         P := 9;
  5342.       end if;
  5343.       if G <= A1(P+4) then
  5344.         P := P + 4;
  5345.       end if;
  5346.       if G <= A1(P+2) then
  5347.         P := P + 2;
  5348.       end if;
  5349.       Z := ((G - A1(P+1)) - A2((P+1)/2))/(G + A1(P+1));
  5350.       Z := Z + Z;
  5351.       V := Z * Z;
  5352.       R := (P2 * V + P1) * V * Z;
  5353.       R := R + K * R;
  5354.       U2 := (R + Z * K) + Z;
  5355.       U1 := FLOAT(INTEGER(M) * 16 - P) * 0.0625;
  5356.       Y1 := REDUCE(Y);
  5357.       Y2 := Y - Y1;
  5358.       W := U2 * Y + U1 * Y2;
  5359.       W1 := REDUCE(W);
  5360.       W2 := W - W1;
  5361.       W := W1 + U1 * Y1;
  5362.       W1 := REDUCE(W);
  5363.       W2 := W2 + (W - W1);
  5364.       W3 := REDUCE(W2);
  5365.       IW1 := INTEGER(TRUNCATE(16.0 * (W1 + W3)));
  5366.       W2 := W2 - W3;
  5367.       if W > FLOAT(IBIGX) then
  5368.         RESULT := XMAX;
  5369.         PUT("X**Y CALLED  X ="); PUT(X); PUT("   Y ="); PUT(Y);
  5370.         PUT("   TOO LARGE  RETURNED "); PUT(RESULT); NEW_LINE;
  5371.       elsif W < FLOAT(ISMALLX) then
  5372.         RESULT := ZERO;
  5373.         PUT("X**Y CALLED  X ="); PUT(X); PUT("   Y ="); PUT(Y);
  5374.         PUT("   TOO SMALL  RETURNED "); PUT(RESULT); NEW_LINE;
  5375.       else
  5376.         if W2 > ZERO then
  5377.           W2 := W2 - 0.0625;
  5378.           IW1 := IW1 + 1;
  5379.         end if;
  5380.         if IW1 < INTEGER(ZERO) then
  5381.           I := 0;
  5382.         else 
  5383.           I := 1;
  5384.         end if;
  5385.         M := EXPONENT_TYPE(I + IW1/16);
  5386.         P := 16 * INTEGER(M) - IW1;
  5387.         Z := ((((Q5 * W2 + Q4) * W2 + Q3) * W2 + Q2) * W2 + Q1) * W2;
  5388.         Z := A1(P+1) + (A1(P+1) * Z);  
  5389.  
  5390.         REFLOAT(M, Z, RESULT);
  5391.       end if;
  5392.     end if;
  5393.     return RESULT;
  5394.   end "**";
  5395.  
  5396. begin
  5397.   EXP_LARGE := LOG(XMAX) * (ONE - EPS);
  5398.   EXP_SMALL := LOG(XMIN) * (ONE - EPS);
  5399. end CORE_FUNCTIONS;
  5400.  
  5401. with TEXT_IO;
  5402. with FLOATING_CHARACTERISTICS;
  5403. with NUMERIC_PRIMITIVES;
  5404. with CORE_FUNCTIONS;
  5405. package body TRIG_FUNCTIONS is
  5406.   use TEXT_IO;
  5407.   use FLOATING_CHARACTERISTICS;
  5408.   use NUMERIC_PRIMITIVES;
  5409.   use CORE_FUNCTIONS;
  5410.   package FLT_IO is new FLOAT_IO(FLOAT);
  5411.   use FLT_IO;
  5412.  
  5413. --  PRELIMINARY VERSION *********************************
  5414.  
  5415. --  The following routines are coded directly from the algorithms and
  5416. --  coeficients given in "Software Manual for the Elementry Functions"
  5417. --  by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980
  5418. --  This particular version is stripped to work with FLOAT and INTEGER
  5419. --  and uses a mantissa represented as a FLOAT
  5420. --  A more general formulation uses MANTISSA_TYPE, etc.
  5421. --  The coeficients are appropriate for 25 to 32 bits floating significance
  5422. --  They will work for less but slightly shorter versions are possible
  5423. --  The routines are coded to stand alone so they need not be compiled together
  5424.  
  5425. --      16 JULY 1982       W A WHITAKER  AFATL EGLIN AFB FL 32542
  5426. --                         T C EICHOLTZ  USAFA
  5427.  
  5428.  
  5429.   function SIN(X : FLOAT) return FLOAT is
  5430.     SGN, Y : FLOAT;
  5431.     N : INTEGER;
  5432.     XN : FLOAT;
  5433.     F, G, X1, X2 : FLOAT;
  5434.     RESULT : FLOAT;
  5435.  
  5436.     YMAX : FLOAT := FLOAT(INTEGER(PI * TWO**(IT/2)));
  5437.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5438.     EPSILON : FLOAT := BETA ** (-IT/2);
  5439.  
  5440.     C1 : constant FLOAT :=  3.140625;
  5441.     C2 : constant FLOAT :=  9.6765_35897_93E-4;
  5442.  
  5443.     function R(G : FLOAT) return FLOAT is
  5444.       R1 : constant FLOAT := -0.16666_66660_883;
  5445.       R2 : constant FLOAT :=  0.83333_30720_556E-2;
  5446.       R3 : constant FLOAT := -0.19840_83282_313E-3;
  5447.       R4 : constant FLOAT :=  0.27523_97106_775E-5;
  5448.       R5 : constant FLOAT := -0.23868_34640_601E-7;
  5449.     begin
  5450.       return ((((R5*G + R4)*G + R3)*G + R2)*G + R1)*G;
  5451.     end R;
  5452.  
  5453.   begin
  5454.     if X < ZERO  then
  5455.       SGN := -ONE;
  5456.       Y := -X;
  5457.     else
  5458.       SGN := ONE;
  5459.       Y := X;
  5460.     end if;
  5461.  
  5462.     if Y > YMAX  then
  5463.       NEW_LINE;
  5464.       PUT(" SIN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
  5465.       PUT(X); NEW_LINE;
  5466.     end if;
  5467.  
  5468.     N := INTEGER(Y * ONE_OVER_PI);
  5469.     XN := CONVERT_TO_FLOAT(N);
  5470.     if N mod 2 /= 0  then
  5471.       SGN := -SGN;
  5472.     end if;
  5473.     X1 := TRUNCATE(ABS(X));
  5474.     X2 := ABS(X) - X1;
  5475.     F := ((X1 - XN*C1) + X2) - XN*C2;
  5476.     if ABS(F) < EPSILON  then
  5477.       RESULT := F;
  5478.     else
  5479.       G := F * F;
  5480.       RESULT := F + F*R(G);
  5481.     end if;
  5482.     return (SGN * RESULT);
  5483.   end SIN;
  5484.  
  5485.  
  5486.   function COS(X : FLOAT) return FLOAT is
  5487.     SGN, Y : FLOAT;
  5488.     N : INTEGER;
  5489.     XN : FLOAT;
  5490.     F, G, X1, X2 : FLOAT;
  5491.     RESULT : FLOAT;
  5492.  
  5493.     YMAX : FLOAT := FLOAT(INTEGER(PI * TWO**(IT/2)));
  5494.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5495.     EPSILON : FLOAT := BETA ** (-IT/2);
  5496.  
  5497.     C1 : constant FLOAT :=  3.140625;
  5498.     C2 : constant FLOAT :=  9.6765_35897_93E-4;
  5499.  
  5500.     function R(G : FLOAT) return FLOAT is
  5501.       R1 : constant FLOAT := -0.16666_66660_883;
  5502.       R2 : constant FLOAT :=  0.83333_30720_556E-2;
  5503.       R3 : constant FLOAT := -0.19840_83282_313E-3;
  5504.       R4 : constant FLOAT :=  0.27523_97106_775E-5;
  5505.       R5 : constant FLOAT := -0.23868_34640_601E-7;
  5506.     begin
  5507.       return ((((R5*G + R4)*G + R3)*G + R2)*G + R1)*G;
  5508.     end R;
  5509.  
  5510.   begin
  5511.     SGN := 1.0;
  5512.     Y := ABS(X) + PI_OVER_TWO;
  5513.  
  5514.     if Y > YMAX  then
  5515.       NEW_LINE;
  5516.       PUT(" COS CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
  5517.       PUT(X); NEW_LINE;
  5518.     end if;
  5519.  
  5520.     N := INTEGER(Y * ONE_OVER_PI);
  5521.     XN := CONVERT_TO_FLOAT(N);
  5522.     if N mod 2 /= 0  then
  5523.       SGN := -SGN;
  5524.     end if;
  5525.     XN := XN - 0.5;          -- TO FORM COS INSTEAD OF SIN
  5526.     X1 := TRUNCATE(ABS(X));
  5527.     X2 := ABS(X) - X1;
  5528.     F := ((X1 - XN*C1) + X2) - XN*C2;
  5529.     if ABS(F) < EPSILON  then
  5530.       RESULT := F;
  5531.     else
  5532.       G := F * F;
  5533.       RESULT := F + F*R(G);
  5534.     end if;
  5535.     return (SGN * RESULT);
  5536.   end COS;
  5537.  
  5538.  
  5539.   function TAN(X : FLOAT) return FLOAT is
  5540.     SGN, Y : FLOAT;
  5541.     N : INTEGER;
  5542.     XN : FLOAT;
  5543.     F, G, X1, X2 : FLOAT;
  5544.     RESULT : FLOAT;
  5545.  
  5546.     YMAX : FLOAT := FLOAT(INTEGER(PI * TWO**(IT/2))) /2.0;
  5547.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5548.     EPSILON : FLOAT := BETA ** (-IT/2);
  5549.  
  5550.     C1 : constant FLOAT :=  8#1.444#;
  5551.     C2 : constant FLOAT :=  4.8382_67948_97E-4;
  5552.  
  5553.     function R(G : FLOAT) return FLOAT is
  5554.       P0 : constant FLOAT :=  1.0;
  5555.       P1 : constant FLOAT := -0.11136_14403_566;
  5556.       P2 : constant FLOAT :=  0.10751_54738_488E-2;
  5557.       Q0 : constant FLOAT :=  1.0;
  5558.       Q1 : constant FLOAT := -0.44469_47720_281;
  5559.       Q2 : constant FLOAT :=  0.15973_39213_300E-1;
  5560.     begin
  5561.       return ((P2*G + P1)*G*F + F) / (((Q2*G + Q1)*G +0.5) + 0.5);
  5562.     end R;
  5563.  
  5564.   begin
  5565.     Y := ABS(X);
  5566.     if Y > YMAX  then
  5567.       NEW_LINE;
  5568.       PUT(" TAN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
  5569.       PUT(X); NEW_LINE;
  5570.     end if;
  5571.  
  5572.     N := INTEGER(X * TWO_OVER_PI);
  5573.     XN := CONVERT_TO_FLOAT(N);
  5574.     X1 := TRUNCATE(X);
  5575.     X2 := X - X1;
  5576.     F := ((X1 - XN*C1) + X2) - XN*C2;
  5577.     if ABS(F) < EPSILON  then
  5578.       RESULT := F;
  5579.     else
  5580.       G := F * F;
  5581.       RESULT := R(G);
  5582.     end if;
  5583.     if N mod 2 = 0  then
  5584.       return RESULT;
  5585.     else
  5586.       return -1.0/RESULT;
  5587.     end if;
  5588.   end TAN;
  5589.  
  5590.   function COT(X : FLOAT) return FLOAT is
  5591.     SGN, Y : FLOAT;
  5592.     N : INTEGER;
  5593.     XN : FLOAT;
  5594.     F, G, X1, X2 : FLOAT;
  5595.     RESULT : FLOAT;
  5596.  
  5597.  
  5598.     YMAX : FLOAT := FLOAT(INTEGER(PI * TWO**(IT/2))) /2.0;
  5599.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5600.     EPSILON : FLOAT := BETA ** (-IT/2);
  5601.     EPSILON1 : FLOAT :=  1.0/XMAX;
  5602.  
  5603.     C1 : constant FLOAT :=  8#1.444#;
  5604.     C2 : constant FLOAT :=  4.8382_67948_97E-4;
  5605.  
  5606.     function R(G : FLOAT) return FLOAT is
  5607.       P0 : constant FLOAT :=  1.0;
  5608.       P1 : constant FLOAT := -0.11136_14403_566;
  5609.       P2 : constant FLOAT :=  0.10751_54738_488E-2;
  5610.       Q0 : constant FLOAT :=  1.0;
  5611.       Q1 : constant FLOAT := -0.44469_47720_281;
  5612.       Q2 : constant FLOAT :=  0.15973_39213_300E-1;
  5613.     begin
  5614.       return ((P2*G + P1)*G*F + F) / (((Q2*G + Q1)*G +0.5) + 0.5);
  5615.     end R;
  5616.  
  5617.   begin
  5618.     Y := ABS(X);
  5619.     if Y < EPSILON1  then
  5620.       NEW_LINE;
  5621.       PUT(" COT CALLED WITH ARGUMENT TOO NEAR ZERO ");
  5622.       PUT(X); NEW_LINE;
  5623.       if X < 0.0  then
  5624.         return -XMAX;
  5625.       else
  5626.         return XMAX;
  5627.       end if;
  5628.     end if;
  5629.     if Y > YMAX  then
  5630.       NEW_LINE;
  5631.       PUT(" COT CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY ");
  5632.       PUT(X); NEW_LINE;
  5633.     end if;
  5634.  
  5635.     N := INTEGER(X * TWO_OVER_PI);
  5636.     XN := CONVERT_TO_FLOAT(N);
  5637.     X1 := TRUNCATE(X);
  5638.     X2 := X - X1;
  5639.     F := ((X1 - XN*C1) + X2) - XN*C2;
  5640.     if ABS(F) < EPSILON  then
  5641.       RESULT := F;
  5642.     else
  5643.       G := F * F;
  5644.       RESULT := R(G);
  5645.     end if;
  5646.     if N mod 2 /= 0  then
  5647.       return -RESULT;
  5648.     else
  5649.       return 1.0/RESULT;
  5650.     end if;
  5651.   end COT;
  5652.  
  5653.  
  5654.   function ASIN(X : FLOAT) return FLOAT is
  5655.     G, Y : FLOAT;
  5656.     RESULT : FLOAT;
  5657.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5658.     EPSILON : FLOAT := BETA ** (-IT/2);
  5659.  
  5660.     function R(G : FLOAT) return FLOAT is
  5661.     P1 : constant FLOAT := -0.27516_55529_0596E1;
  5662.     P2 : constant FLOAT :=  0.29058_76237_4859E1;
  5663.     P3 : constant FLOAT := -0.59450_14419_3246;
  5664.     Q0 : constant FLOAT := -0.16509_93320_2424E2;
  5665.     Q1 : constant FLOAT :=  0.24864_72896_9164E2;
  5666.     Q2 : constant FLOAT := -0.10333_86707_2113E2;
  5667.     Q3 : constant FLOAT :=  1.0;
  5668.     begin
  5669.       return (((P3*G + P2)*G + P1)*G) / (((G + Q2)*G + Q1)*G + Q0);
  5670.     end R;
  5671.  
  5672.   begin
  5673.     Y := ABS(X);
  5674.  
  5675.     if Y > HALF  then
  5676.       if Y > 1.0  then
  5677.         NEW_LINE; PUT(" ASIN CALLED FOR "); PUT(X);
  5678.             PUT(" (> 1)  TRUNCATED TO 1, CONTINUED"); NEW_LINE;
  5679.         Y := 1.0;
  5680.       end if;
  5681.       G := ((0.5 - Y) + 0.5) / 2.0;
  5682.       Y := -2.0 * SQRT(G);
  5683.       RESULT := Y + Y * R(G);
  5684.       RESULT := (PI_OVER_FOUR + RESULT) + PI_OVER_FOUR;
  5685.     else
  5686.       if Y < EPSILON  then
  5687.         RESULT := Y;
  5688.       else
  5689.         G := Y * Y;
  5690.         RESULT := Y + Y * R(G);
  5691.       end if;
  5692.     end if;
  5693.     if X < 0.0  then
  5694.       RESULT := -RESULT;
  5695.     end if;
  5696.  
  5697.     return RESULT;
  5698.   end ASIN;
  5699.  
  5700.   function ACOS(X : FLOAT) return FLOAT is
  5701.     G, Y : FLOAT;
  5702.     RESULT : FLOAT;
  5703.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5704.     EPSILON : FLOAT := BETA ** (-IT/2);
  5705.  
  5706.     function R(G : FLOAT) return FLOAT is
  5707.     P1 : constant FLOAT := -0.27516_55529_0596E1;
  5708.     P2 : constant FLOAT :=  0.29058_76237_4859E1;
  5709.     P3 : constant FLOAT := -0.59450_14419_3246;
  5710.     Q0 : constant FLOAT := -0.16509_93320_2424E2;
  5711.     Q1 : constant FLOAT :=  0.24864_72896_9164E2;
  5712.     Q2 : constant FLOAT := -0.10333_86707_2113E2;
  5713.     Q3 : constant FLOAT :=  1.0;
  5714.     begin
  5715.       return (((P3*G + P2)*G + P1)*G) / (((G + Q2)*G + Q1)*G + Q0);
  5716.     end R;
  5717.  
  5718.   begin
  5719.     Y := ABS(X);
  5720.  
  5721.     if Y > HALF  then
  5722.       if Y > 1.0  then
  5723.         NEW_LINE; PUT(" ACOS CALLED FOR "); PUT(X);
  5724.             PUT(" (> 1)  TRUNCATED TO 1, CONTINUED"); NEW_LINE;
  5725.         Y := 1.0;
  5726.       end if;
  5727.       G := ((0.5 - Y) + 0.5) / 2.0;
  5728.       Y := -2.0 * SQRT(G);
  5729.       RESULT := Y + Y * R(G);
  5730.       if X < 0.0  then
  5731.         RESULT := (PI_OVER_TWO + RESULT) + PI_OVER_TWO;
  5732.       else
  5733.         RESULT := -RESULT;
  5734.       end if;
  5735.  
  5736.     else
  5737.       if Y < EPSILON  then
  5738.         RESULT := Y;
  5739.       else
  5740.         G := Y * Y;
  5741.         RESULT := Y + Y * R(G);
  5742.       end if;
  5743.       if X < 0.0  then
  5744.         RESULT := (PI_OVER_FOUR + RESULT) + PI_OVER_FOUR;
  5745.       else
  5746.         RESULT := (PI_OVER_FOUR - RESULT) + PI_OVER_FOUR;
  5747.       end if;
  5748.     end if;
  5749.  
  5750.     return RESULT;
  5751.   end ACOS;
  5752.  
  5753.  
  5754.   function ATAN(X : FLOAT) return FLOAT is
  5755.     F, G : FLOAT;
  5756.     subtype REGION is INTEGER range 0..3;    --  ##########
  5757.     N : REGION;
  5758.     RESULT : FLOAT;
  5759.  
  5760.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5761.  
  5762.     EPSILON : FLOAT := BETA ** (-IT/2);
  5763.  
  5764.     SQRT_3           : constant FLOAT :=  1.73205_08075_68877_29353;
  5765.     SQRT_3_MINUS_1   : constant FLOAT :=  0.73205_08075_68877_29353;
  5766.     TWO_MINUS_SQRT_3 : constant FLOAT :=  0.26794_91924_31122_70647;
  5767.  
  5768.     function R(G : FLOAT) return FLOAT is
  5769.       P0 : constant FLOAT := -0.14400_83448_74E1;
  5770.       P1 : constant FLOAT := -0.72002_68488_98;
  5771.       Q0 : constant FLOAT :=  0.43202_50389_19E1;
  5772.       Q1 : constant FLOAT :=  0.47522_25845_99E1;
  5773.       Q2 : constant FLOAT :=  1.0;
  5774.     begin
  5775.       return ((P1*G + P0)*G) / ((G + Q1)*G + Q0);
  5776.     end R;
  5777.  
  5778.   begin
  5779.     F := ABS(X);
  5780.  
  5781.     if F > 1.0  then
  5782.       F := 1.0 / F;
  5783.       N := 2;
  5784.     else
  5785.       N := 0;
  5786.     end if;
  5787.  
  5788.     if F > TWO_MINUS_SQRT_3  then
  5789.       F := (((SQRT_3_MINUS_1 * F - 0.5) - 0.5) + F) / (SQRT_3 + F);
  5790.       N := N + 1;
  5791.     end if;
  5792.  
  5793.     if ABS(F) < EPSILON  then
  5794.       RESULT := F;
  5795.     else
  5796.       G := F * F;
  5797.       RESULT := F + F * R(G);
  5798.     end if;
  5799.  
  5800.     if N > 1  then
  5801.       RESULT := - RESULT;
  5802.     end if;
  5803.  
  5804.     case N is
  5805.     when 0  =>
  5806.       RESULT := RESULT;
  5807.     when 1  =>
  5808.       RESULT := PI_OVER_SIX + RESULT;
  5809.     when 2  =>
  5810.       RESULT := PI_OVER_TWO + RESULT;
  5811.     when 3  =>
  5812.       RESULT := PI_OVER_THREE + RESULT;
  5813.     end case;
  5814.  
  5815.     if X < 0.0  then
  5816.       RESULT := - RESULT;
  5817.     end if;
  5818.  
  5819.     return RESULT;
  5820.  
  5821.   end ATAN;
  5822.  
  5823.  
  5824.  
  5825.   function ATAN2(V, U : FLOAT) return FLOAT is
  5826.     X, RESULT : FLOAT;
  5827.  
  5828.   begin
  5829.  
  5830.     if U = 0.0  then
  5831.       if V = 0.0  then
  5832.         RESULT := 0.0;
  5833.         NEW_LINE;
  5834.         PUT(" ATAN2 CALLED WITH 0/0   RETURNED "); PUT(RESULT);
  5835.         NEW_LINE;
  5836.       elsif V > 0.0  then
  5837.         RESULT := PI_OVER_TWO;
  5838.       else
  5839.         RESULT := - PI_OVER_TWO;
  5840.       end if;
  5841.  
  5842.     else
  5843.       X := ABS(V/U);
  5844.       --  If underflow or overflow is detected, go to the exception
  5845.       RESULT := ATAN(X);
  5846.       if U < 0.0  then
  5847.         RESULT := PI - RESULT;
  5848.       end if;
  5849.       if V < 0.0  then
  5850.         RESULT := - RESULT;
  5851.       end if;
  5852.     end if;
  5853.     return RESULT;
  5854.   exception
  5855.   when NUMERIC_ERROR | CONSTRAINT_ERROR  =>
  5856.     if ABS(V) > ABS(U)  then
  5857.       RESULT := PI_OVER_TWO;
  5858.       if V < 0.0  then
  5859.         RESULT := - RESULT;
  5860.       end if;
  5861.     else
  5862.       RESULT := 0.0;
  5863.       if U < 0.0  then
  5864.         RESULT := PI - RESULT;
  5865.       end if;
  5866.     end if;
  5867.     return RESULT;
  5868.   end ATAN2;
  5869.  
  5870.  
  5871.   function SINH(X : FLOAT) return FLOAT is
  5872.     G, W, Y, Z : FLOAT;
  5873.     RESULT : FLOAT;
  5874.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5875.     EPSILON : FLOAT := BETA ** (-IT/2);
  5876.  
  5877.     YBAR : FLOAT := EXP_LARGE;
  5878.     LN_V : FLOAT := 8#0.542714#;
  5879.     V_OVER_2_MINUS_1 : FLOAT :=  0.13830_27787_96019_02638E-4;
  5880.     WMAX : FLOAT := YBAR - LN_V + 0.69;
  5881.  
  5882.     function R(G : FLOAT) return FLOAT is
  5883.     P0 : constant FLOAT :=  0.10622_28883_7151E4;
  5884.     P1 : constant FLOAT :=  0.31359_75645_6058E2;
  5885.     P2 : constant FLOAT :=  0.34364_14035_8506;
  5886.     Q0 : constant FLOAT :=  0.63733_73302_1822E4;
  5887.     Q1 : constant FLOAT := -0.13051_01250_9199E3;
  5888.     Q2 : constant FLOAT :=  1.0;
  5889.     begin
  5890.       return (((P2*G + P1)*G + P0)*G) / ((G + Q1)*G + Q0);
  5891.     end R;
  5892.  
  5893.   begin
  5894.     Y := ABS(X);
  5895.  
  5896.     if Y <= 1.0  then
  5897.       if Y < EPSILON  then
  5898.         RESULT := X;
  5899.       else
  5900.         G := X * X;
  5901.         RESULT := X + X * R(G);
  5902.       end if;
  5903.  
  5904.     else
  5905.       if Y <= YBAR  then
  5906.         Z := EXP(Y);
  5907.         RESULT := (Z - 1.0/Z) / 2.0;
  5908.       else
  5909.         W := Y - LN_V;
  5910.         if W > WMAX  then
  5911.           NEW_LINE;
  5912.           PUT(" SINH CALLED WITH TOO LARGE ARGUMENT  "); PUT(X);
  5913.           PUT(" RETURN BIG"); NEW_LINE;
  5914.           W := WMAX;
  5915.         end if;
  5916.         Z := EXP(W);
  5917.         RESULT := Z + V_OVER_2_MINUS_1 * Z;
  5918.       end if;
  5919.       if X < 0.0  then
  5920.         RESULT := -RESULT;
  5921.       end if;
  5922.  
  5923.     end if;
  5924.     return RESULT;
  5925.   end SINH;
  5926.  
  5927.  
  5928.   function COSH(X : FLOAT) return FLOAT is
  5929.     G, W, Y, Z : FLOAT;
  5930.     RESULT : FLOAT;
  5931.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5932.     EPSILON : FLOAT := BETA ** (-IT/2);
  5933.  
  5934.     YBAR : FLOAT := EXP_LARGE;
  5935.     LN_V : FLOAT := 8#0.542714#;
  5936.     V_OVER_2_MINUS_1 : FLOAT :=  0.13830_27787_96019_02638E-4;
  5937.     WMAX : FLOAT := YBAR - LN_V + 0.69;
  5938.  
  5939.     function R(G : FLOAT) return FLOAT is
  5940.     P0 : constant FLOAT :=  0.10622_28883_7151E4;
  5941.     P1 : constant FLOAT :=  0.31359_75645_6058E2;
  5942.     P2 : constant FLOAT :=  0.34364_14035_8506;
  5943.     Q0 : constant FLOAT :=  0.63733_73302_1822E4;
  5944.     Q1 : constant FLOAT := -0.13051_01250_9199E3;
  5945.     Q2 : constant FLOAT :=  1.0;
  5946.     begin
  5947.       return (((P2*G + P1)*G + P0)*G) / ((G + Q1)*G + Q0);
  5948.     end R;
  5949.  
  5950.   begin
  5951.     Y := ABS(X);
  5952.  
  5953.     if Y <= YBAR  then
  5954.       Z := EXP(Y);
  5955.       RESULT := (Z + 1.0/Z) / 2.0;
  5956.     else
  5957.       W := Y - LN_V;
  5958.       if W > WMAX  then
  5959.         NEW_LINE;
  5960.         PUT(" COSH CALLED WITH TOO LARGE ARGUMENT  "); PUT(X);
  5961.         PUT(" RETURN BIG"); NEW_LINE;
  5962.         W := WMAX;
  5963.       end if;
  5964.       Z := EXP(W);
  5965.       RESULT := Z + V_OVER_2_MINUS_1 * Z;
  5966.     end if;
  5967.  
  5968.     return RESULT;
  5969.   end COSH;
  5970.  
  5971.  
  5972.   function TANH(X : FLOAT) return FLOAT is
  5973.     G, W, Y, Z : FLOAT;
  5974.     RESULT : FLOAT;
  5975.     BETA : FLOAT := CONVERT_TO_FLOAT(IBETA);
  5976.     EPSILON : FLOAT := BETA ** (-IT/2);
  5977.  
  5978.     XBIG : FLOAT := (LOG(2.0) + CONVERT_TO_FLOAT(IT + 1) * LOG(BETA))/2.0;
  5979.     LN_3_OVER_2 : FLOAT :=  0.54930_61443_34054_84570;
  5980.  
  5981.     function R(G : FLOAT) return FLOAT is
  5982.     P0 : constant FLOAT := -0.21063_95800_0245E2;
  5983.     P1 : constant FLOAT := -0.93363_47565_2401;
  5984.     Q0 : constant FLOAT :=  0.63191_87401_5582E2;
  5985.     Q1 : constant FLOAT :=  0.28077_65347_0471E2;
  5986.     Q2 : constant FLOAT :=  1.0;
  5987.     begin
  5988.       return ((P1*G + P0)*G) / ((G + Q1)*G + Q0);
  5989.     end R;
  5990.  
  5991.   begin
  5992.     Y := ABS(X);
  5993.  
  5994.     if Y > XBIG  then
  5995.       RESULT := 1.0;
  5996.     else
  5997.       if Y > LN_3_OVER_2  then
  5998.         RESULT := 0.5 - 1.0 / (EXP(Y + Y) + 1.0);
  5999.         RESULT := RESULT + RESULT;
  6000.       else
  6001.         if Y < EPSILON  then
  6002.           RESULT := Y;
  6003.         else
  6004.           G := Y * Y;
  6005.           RESULT := Y + Y * R(G);
  6006.         end if;
  6007.       end if;
  6008.     end if;
  6009.     if X < 0.0  then
  6010.       RESULT := - RESULT;
  6011.     end if;
  6012.  
  6013.     return RESULT;
  6014.   end TANH;
  6015.  
  6016.  
  6017. begin
  6018.   null;
  6019. end TRIG_FUNCTIONS;
  6020. --::::::::::
  6021. --out.bdy
  6022. --::::::::::
  6023. -- **********************************
  6024. -- *                                *
  6025. -- *  Output_File                   *  BODY
  6026. -- *                                *
  6027. -- **********************************
  6028. with Text_IO;
  6029. package body Output_File is
  6030.  
  6031. --| Notes (none)
  6032. --|
  6033. --| Modifications
  6034. --| 08/16/89  Rick Conn    Initial Version
  6035.  
  6036.   type FILE_OBJECT is
  6037.     record
  6038.       File           : Text_IO.File_Type;
  6039.       Is_Open        : BOOLEAN      := false;
  6040.       Is_Output_Enabled : BOOLEAN   := true;
  6041.     end record;
  6042.  
  6043.   -- ..................................
  6044.   -- .                                .
  6045.   -- .  Already_Exists                .  BODY
  6046.   -- .                                .
  6047.   -- ..................................
  6048.   function Already_Exists
  6049.     ( File_Name      : in STRING )
  6050.     return BOOLEAN is
  6051.  
  6052.   --| Notes (none)
  6053.  
  6054.     File
  6055.       : Text_IO.File_Type;
  6056.  
  6057.     Result
  6058.       : BOOLEAN
  6059.         := true;
  6060.  
  6061.   begin -- Already_Exists
  6062.  
  6063.     begin
  6064.       Text_IO.Open(File, Text_IO.In_File, File_Name);
  6065.       Text_IO.Close(File);
  6066.     exception
  6067.       when others =>
  6068.         Result := false;
  6069.     end;
  6070.     return Result;
  6071.  
  6072.   end Already_Exists;
  6073.  
  6074.   -- ..................................
  6075.   -- .                                .
  6076.   -- .  Delete                        .  BODY
  6077.   -- .                                .
  6078.   -- ..................................
  6079.   function Delete
  6080.     ( File_Name      : in STRING )
  6081.     return BOOLEAN is
  6082.  
  6083.   --| Notes (none)
  6084.  
  6085.     File
  6086.       : Text_IO.File_Type;
  6087.  
  6088.     Result
  6089.       : BOOLEAN
  6090.         := true;
  6091.  
  6092.   begin -- Delete
  6093.  
  6094.     begin
  6095.       if Already_Exists(File_Name) then
  6096.         Text_IO.Open(File, Text_IO.Out_File, File_Name);
  6097.         Text_IO.Delete(File);
  6098.       end if;
  6099.  
  6100.     exception
  6101.       when others =>
  6102.         Result := false;
  6103.     end;
  6104.     return Result;
  6105.  
  6106.   end Delete;
  6107.  
  6108.   -- ..................................
  6109.   -- .                                .
  6110.   -- .  Create                        .  BODY
  6111.   -- .                                .
  6112.   -- ..................................
  6113.   procedure Create
  6114.     ( Id             : in out File_Type;
  6115.       File_Name      : in STRING ) is
  6116.  
  6117.   --| Notes (none)
  6118.  
  6119.   begin -- Create
  6120.  
  6121.     Id             := new FILE_OBJECT;
  6122.     Text_IO.Create(Id.File, Text_IO.Out_File, File_Name);
  6123.     Id.Is_Open     := true;
  6124.     Id.Is_Output_Enabled := true;
  6125.  
  6126.   exception -- Create -- Create
  6127.     when others =>
  6128.       raise Cannot_Create_Output_File;
  6129.  
  6130.   end Create;
  6131.  
  6132.   -- ..................................
  6133.   -- .                                .
  6134.   -- .  Put                           .  BODY
  6135.   -- .                                .
  6136.   -- ..................................
  6137.   procedure Put
  6138.     ( Id             : in out File_Type;
  6139.       Item           : in CHARACTER ) is
  6140.  
  6141.   --| Notes (none)
  6142.  
  6143.   begin -- Put
  6144.  
  6145.     if Id.Is_Open and Id.Is_Output_Enabled then
  6146.       Text_IO.Put(Id.File, Item);
  6147.     end if;
  6148.  
  6149.   exception -- Put -- Put
  6150.     when others =>
  6151.       raise Write_Error;
  6152.  
  6153.   end Put;
  6154.  
  6155.   -- ..................................
  6156.   -- .                                .
  6157.   -- .  Put                           .  BODY
  6158.   -- .                                .
  6159.   -- ..................................
  6160.   procedure Put
  6161.     ( Id             : in out File_Type;
  6162.       Item           : in STRING ) is
  6163.  
  6164.   --| Notes (none)
  6165.  
  6166.   begin -- Put
  6167.  
  6168.     if Id.Is_Open and Id.Is_Output_Enabled then
  6169.       Text_IO.Put(Id.File, Item);
  6170.     end if;
  6171.  
  6172.   exception -- Put -- Put
  6173.     when others =>
  6174.       raise Write_Error;
  6175.  
  6176.   end Put;
  6177.  
  6178.   -- ..................................
  6179.   -- .                                .
  6180.   -- .  Put_Line                      .  BODY
  6181.   -- .                                .
  6182.   -- ..................................
  6183.   procedure Put_Line
  6184.     ( Id             : in out File_Type;
  6185.       Item           : in STRING ) is
  6186.  
  6187.   --| Notes (none)
  6188.  
  6189.   begin -- Put_Line
  6190.  
  6191.     if Id.Is_Open and Id.Is_Output_Enabled then
  6192.       Text_IO.Put_Line(Id.File, Item);
  6193.     end if;
  6194.  
  6195.   exception -- Put_Line -- Put_Line
  6196.     when others =>
  6197.       raise Write_Error;
  6198.  
  6199.   end Put_Line;
  6200.  
  6201.   -- ..................................
  6202.   -- .                                .
  6203.   -- .  New_Line                      .  BODY
  6204.   -- .                                .
  6205.   -- ..................................
  6206.   procedure New_Line
  6207.     ( Id             : in out File_Type ) is
  6208.  
  6209.   --| Notes (none)
  6210.  
  6211.   begin -- New_Line
  6212.  
  6213.     if Id.Is_Open and Id.Is_Output_Enabled then
  6214.       Text_IO.New_Line(Id.File);
  6215.     end if;
  6216.  
  6217.   exception -- New_Line -- New_Line
  6218.     when others =>
  6219.       raise Write_Error;
  6220.  
  6221.   end New_Line;
  6222.  
  6223.   -- ..................................
  6224.   -- .                                .
  6225.   -- .  New_Page                      .  BODY
  6226.   -- .                                .
  6227.   -- ..................................
  6228.   procedure New_Page
  6229.     ( Id             : in out File_Type ) is
  6230.  
  6231.   --| Notes (none)
  6232.  
  6233.   begin -- New_Page
  6234.  
  6235.     if Id.Is_Open and Id.Is_Output_Enabled then
  6236.       Text_IO.New_Page(Id.File);
  6237.     end if;
  6238.  
  6239.   exception -- New_Page -- New_Page
  6240.     when others =>
  6241.       raise Write_Error;
  6242.  
  6243.   end New_Page;
  6244.  
  6245.   -- ..................................
  6246.   -- .                                .
  6247.   -- .  Enable_Output                 .  BODY
  6248.   -- .                                .
  6249.   -- ..................................
  6250.   procedure Enable_Output
  6251.     ( Id             : in out File_Type ) is
  6252.  
  6253.   --| Notes (none)
  6254.  
  6255.   begin -- Enable_Output
  6256.  
  6257.     Id.Is_Output_Enabled := true;
  6258.  
  6259.   end Enable_Output;
  6260.  
  6261.   -- ..................................
  6262.   -- .                                .
  6263.   -- .  Disable_Output                .  BODY
  6264.   -- .                                .
  6265.   -- ..................................
  6266.   procedure Disable_Output
  6267.     ( Id             : in out File_Type ) is
  6268.  
  6269.   --| Notes (none)
  6270.  
  6271.   begin -- Disable_Output
  6272.  
  6273.     Id.Is_Output_Enabled := false;
  6274.  
  6275.   end Disable_Output;
  6276.  
  6277.   -- ..................................
  6278.   -- .                                .
  6279.   -- .  Close                         .  BODY
  6280.   -- .                                .
  6281.   -- ..................................
  6282.   procedure Close
  6283.     ( Id             : in out File_Type ) is
  6284.  
  6285.   --| Notes (none)
  6286.  
  6287.   begin -- Close
  6288.  
  6289.     if Id.Is_Open then
  6290.       Text_IO.Close(Id.File);
  6291.     end if;
  6292.  
  6293.   end Close;
  6294.  
  6295. end Output_File;
  6296. --::::::::::
  6297. --permutat.bdy
  6298. --::::::::::
  6299. package body Permutations_Class is
  6300.  
  6301.     -----------------------------
  6302.     -- Basic algorithm from:
  6303.     --       "Programming in Modula-2" by Niklaus Wirth
  6304.     --       Chapter 14: Recursion
  6305.     -----------------------------
  6306.     -- The procedure permutes the elements in the array ITEMS.
  6307.     -- actually it permutes their indicies and re-arranges the items
  6308.     -- within the list.  The procedure does not care of any or all
  6309.     -- of the items in the list are equal (the same).
  6310.     -----------------------------
  6311.  
  6312.     procedure Iterate_Through_Length_Factorial_Permutations
  6313.          (Of_Items : List_Type) is
  6314.  
  6315.     Buffer : List_Type (Of_Items'Range) := Of_Items;
  6316.  
  6317.     ---------------------
  6318.     procedure Permute (K_Th : Index_Type) is
  6319.     -- Swap successive elements of Buffer (Buffer'first .. K_th)
  6320.     -- and permute slices. This algorithm works backwords
  6321.     -- through the array (in reverse Buffer'range).
  6322.         Temp : Item_Type;
  6323.     begin
  6324.         if K_Th = Buffer'First then
  6325.         -- At the begining of the array. Done.  Process result.
  6326.         Process (A_Permutation => Buffer);
  6327.         else
  6328.         --Decrement K and permute lower slice.
  6329.         Permute (Index_Type'Pred (K_Th));
  6330.  
  6331.         -- Traverse lower slice.
  6332.         for I_Th in Buffer'First .. Index_Type'Pred (K_Th) loop
  6333.             -- swap K-th and I-th elements.
  6334.             Temp := Buffer (I_Th);
  6335.             Buffer (I_Th) := Buffer (K_Th);
  6336.             Buffer (K_Th) := Temp;
  6337.  
  6338.             -- Decrement K and permute lower slice.
  6339.             Permute (Index_Type'Pred (K_Th));
  6340.  
  6341.             -- swap K-th and I-th elements back (restore).
  6342.             Temp := Buffer (I_Th);
  6343.             Buffer (I_Th) := Buffer (K_Th);
  6344.             Buffer (K_Th) := Temp;
  6345.         end loop;
  6346.         end if;
  6347.     end Permute;
  6348.     ---------------------
  6349.     begin
  6350.     -- iterate_through_length_factorial_permutations
  6351.     Permute (Buffer'Last);
  6352.     end Iterate_Through_Length_Factorial_Permutations;
  6353.  
  6354. end Permutations_Class;
  6355. --::::::::::
  6356. --priqueue.bdy
  6357. --::::::::::
  6358. with UNCHECKED_DEALLOCATION;
  6359.  
  6360. package body PRIORITIZED_QUEUE is
  6361.  
  6362.    --  *************************************************************************************
  6363.    --  **  This software is part of the Clemson University Computer Science Department's  **
  6364.    --  **  Ada Software Repository, and is copyrighted (C) 1989 by Clemson University.    **
  6365.    --  **  Permission to copy without fee all or part of this software is granted,        **
  6366.    --  **  provided that the copies are not made or distributed for direct commercial     **
  6367.    --  **  advantage, and that this copyright notice is not deleted or modified.  To      **
  6368.    --  **  copy otherwise, or to republish, requires a fee and/or specific permission.    **
  6369.    --  **  >> All bug reporters receive a free updated copy once the bug's corrected! <<  ** 
  6370.    --  **  E-mail to: cpscada@citron.cs.clemson.edu or ...!gatech!hubcap!citron!cpscada.  **
  6371.    --  *************************************************************************************
  6372.  
  6373.    --    type ENQUEUED_OBJECT is limited private;
  6374.    --
  6375.    --    type PRIORITY_VALUE is (<>);
  6376.    --
  6377.    --    with procedure ASSIGN (TARGET : in out ENQUEUED_OBJECT;
  6378.    --                           SOURCE : in     ENQUEUED_OBJECT) is <>;
  6379.    --
  6380.    --    with function "=" (FIRST_OBJECT  : in ENQUEUED_OBJECT;
  6381.    --                       SECOND_OBJECT : in ENQUEUED_OBJECT) return BOOLEAN is <>;
  6382.    --
  6383.    --    with procedure DESTROY (TARGETED_OBJECT : in out ENQUEUED_OBJECT) is <>;
  6384.    --
  6385.    -- -- with procedure ":=" (TARGET_OBJECT : in out PRIORITY_VALUE;                -- implicitly available...
  6386.    -- --                      SOURCE_OBJECT : in     PRIORITY_VALUE) is <>; 
  6387.    --
  6388.    --    with function "<" (FIRST_OBJECT  : in PRIORITY_VALUE;
  6389.    --                       SECOND_OBJECT : in PRIORITY_VALUE) return BOOLEAN is <>;
  6390.    --
  6391.    -- -- with function "=" (FIRST_OBJECT  : in PRIORITY_VALUE;                      -- implicitly available...
  6392.    -- --                    SECOND_OBJECT : in PRIORITY_VALUE) return BOOLEAN is <>;
  6393.    --
  6394.    --    Requested_Item_Does_Not_Exist_In_This_Priority_Queue  : EXCEPTION;
  6395.    --    No_Items_Currently_Exist_In_This_Empty_Priority_Queue : EXCEPTION;
  6396.    --
  6397.    --    type PRIORITY_QUEUE_NODE;
  6398.    --
  6399.    --    type PRIORITY_QUEUE is access PRIORITY_QUEUE_NODE;   
  6400.    --
  6401.    --       -- requires O (n) space, where n is the NUMBER_OF_ITEMS in the queue...
  6402.  
  6403.    subtype PRIORITY_QUEUE_NODE_POINTER is PRIORITY_QUEUE;
  6404.  
  6405.    type PRIORITY_QUEUE_NODE is
  6406.  
  6407.       record
  6408.          ENQUEUED_ENTITY   : ENQUEUED_OBJECT;
  6409.          ENTITY_PRIORITY   : PRIORITY_VALUE;
  6410.          LEFTMOST_CHILD    : PRIORITY_QUEUE_NODE_POINTER; 
  6411.          SIBLING           : PRIORITY_QUEUE_NODE_POINTER;
  6412.       end record;
  6413.  
  6414.       -- Our representation is as follows: A priority queue is a binomial forest (see CACM, Vol. 21, No. 4, pages 309-314).
  6415.       -- The type PRIORITY_QUEUE points to the root node of the smallest binomial tree in the forest.  The SIBLING 
  6416.       -- of this node points to the next larger tree in the forest.  The sibling of the largest tree in the forest is null.
  6417.       -- At the root level, the SIBLING field points to the leftward sibling of a given binomial tree in a forest.  At
  6418.       -- any other level, the SIBLING field points to the rightward sibling of a given child, in the traditional manner.
  6419.       --
  6420.       -- This implementation has been carefully hand-optimized, and should be VERY fast, with little room for improvement.
  6421.  
  6422.    function NUMBER_OF_CHILDREN (TARGETED_NODE : PRIORITY_QUEUE_NODE_POINTER) return NATURAL is
  6423.  
  6424.       -- TARGETED_NODE must not be null...
  6425.  
  6426.       NUMBER_OF_CHILDREN_FOUND : NATURAL := 0;
  6427.       CURRENT_CHILD            : PRIORITY_QUEUE_NODE_POINTER := TARGETED_NODE.LEFTMOST_CHILD;
  6428.  
  6429.    begin
  6430.        while (CURRENT_CHILD /= null) loop
  6431.           NUMBER_OF_CHILDREN_FOUND := NUMBER_OF_CHILDREN_FOUND + 1;
  6432.           CURRENT_CHILD := CURRENT_CHILD.SIBLING; 
  6433.        end loop;
  6434.       return NUMBER_OF_CHILDREN_FOUND;
  6435.    end NUMBER_OF_CHILDREN;
  6436.  
  6437.  
  6438.    procedure ADD_WITH_CARRY (CURRENT_TREE : in out PRIORITY_QUEUE_NODE_POINTER;
  6439.                              TREE_TO_ADD  : in out PRIORITY_QUEUE_NODE_POINTER) is
  6440.  
  6441.       -- CURRENT_TREE must be the only pointer to the smallest tree in a given forest whose root has 
  6442.       --   at least as many children as the root of the TREE_TO_ADD, subject to the constraint 
  6443.       --   that the number of children associated with the root of CURRENT_TREE is not zero. 
  6444.  
  6445.       CHILD_COUNTER       : POSITIVE := 1;
  6446.       CHILD_COUNT_SCANNER : PRIORITY_QUEUE_NODE_POINTER;
  6447.  
  6448.    begin
  6449.  
  6450.       loop
  6451.  
  6452.          CHILD_COUNT_SCANNER := CURRENT_TREE.LEFTMOST_CHILD.SIBLING;  -- we know that CURRENT_TREE must have 
  6453.          while (CHILD_COUNTER /= 1) loop                              --   at least as many kids as TREE_TO_ADD... 
  6454.             CHILD_COUNT_SCANNER := CHILD_COUNT_SCANNER.SIBLING;
  6455.             CHILD_COUNTER := CHILD_COUNTER - 1;
  6456.          end loop; 
  6457.  
  6458.          exit when (CHILD_COUNT_SCANNER /= null);   -- CURRENT_TREE has more kids than TREE_TO_ADD; room in forest...
  6459.  
  6460.          if (TREE_TO_ADD.ENTITY_PRIORITY < CURRENT_TREE.ENTITY_PRIORITY) then   -- make TREE_TO_ADD a child of CURRENT_TREE...
  6461.             TREE_TO_ADD.SIBLING := CURRENT_TREE.LEFTMOST_CHILD;  -- maintaining *rightward* links within a tree...
  6462.             CURRENT_TREE.LEFTMOST_CHILD := TREE_TO_ADD;
  6463.             TREE_TO_ADD := CURRENT_TREE;
  6464.             CURRENT_TREE := CURRENT_TREE.SIBLING;     
  6465.          else   -- make CURRENT_TREE a child of TREE_TO_ADD...
  6466.             TREE_TO_ADD.SIBLING := CURRENT_TREE.SIBLING;        -- maintaining *leftward* links among trees in the forest... 
  6467.             CURRENT_TREE.SIBLING := TREE_TO_ADD.LEFTMOST_CHILD; -- maintaining *rightward* links within a tree...
  6468.             TREE_TO_ADD.LEFTMOST_CHILD := CURRENT_TREE;
  6469.             CURRENT_TREE := TREE_TO_ADD.SIBLING;      
  6470.          end if;
  6471.  
  6472.          exit when (CURRENT_TREE = null);   -- we've reached the end of the forest...
  6473.  
  6474.          CHILD_COUNT_SCANNER := TREE_TO_ADD.LEFTMOST_CHILD.SIBLING;
  6475.          while (CHILD_COUNT_SCANNER /= null) loop                       -- count the children in the TREE_TO_ADD...
  6476.             CHILD_COUNTER := CHILD_COUNTER + 1;
  6477.             CHILD_COUNT_SCANNER := CHILD_COUNT_SCANNER.SIBLING;
  6478.          end loop;
  6479.  
  6480.       end loop;
  6481.  
  6482.       TREE_TO_ADD.SIBLING := CURRENT_TREE;     -- maintaining *leftward* links among trees in the forest... 
  6483.       CURRENT_TREE := TREE_TO_ADD;
  6484.  
  6485.    end ADD_WITH_CARRY;
  6486.  
  6487.    procedure INSERT_ITEM (QUEUE    : in out PRIORITY_QUEUE;
  6488.                           OBJECT   : in     ENQUEUED_OBJECT;
  6489.                           PRIORITY : in     PRIORITY_VALUE) is
  6490.  
  6491.       -- The QUEUE can safely handle multiple instances of a given (OBJECT, PRIORITY) pair.
  6492.       -- Works in O (log n) time, where n is the NUMBER_OF_ITEMS in the updated QUEUE.
  6493.       -- A series of consecutive initializing insertions uses O (n) time, where n is the number of insertions.
  6494.  
  6495.       NEW_ITEM : PRIORITY_QUEUE_NODE_POINTER := new PRIORITY_QUEUE_NODE;
  6496.  
  6497.    begin
  6498.       ASSIGN (NEW_ITEM.ENQUEUED_ENTITY, OBJECT);
  6499.       NEW_ITEM.ENTITY_PRIORITY := PRIORITY;
  6500.       if (QUEUE = null) then    -- the new item becomes the only tree in the forest
  6501.          QUEUE := NEW_ITEM;
  6502.       elsif (QUEUE.LEFTMOST_CHILD /= null) then    -- just insert the new smallest tree directly into the forest...
  6503.          NEW_ITEM.SIBLING := QUEUE;
  6504.          QUEUE := NEW_ITEM;
  6505.       else 
  6506.          ADD_WITH_CARRY (QUEUE, NEW_ITEM);   
  6507.       end if;
  6508.    end INSERT_ITEM;
  6509.  
  6510.  
  6511.    function ADD (FIRST_TREE  : in PRIORITY_QUEUE_NODE_POINTER;
  6512.                  SECOND_TREE : in PRIORITY_QUEUE_NODE_POINTER) return PRIORITY_QUEUE_NODE_POINTER is
  6513.  
  6514.       -- Merges the two trees into a single tree, returning the pointer to the unified tree.
  6515.  
  6516.    begin
  6517.       if (SECOND_TREE.ENTITY_PRIORITY < FIRST_TREE.ENTITY_PRIORITY) then
  6518.          SECOND_TREE.SIBLING := FIRST_TREE.LEFTMOST_CHILD;
  6519.          FIRST_TREE.LEFTMOST_CHILD := SECOND_TREE;
  6520.          return FIRST_TREE;
  6521.       else
  6522.          FIRST_TREE.SIBLING := SECOND_TREE.LEFTMOST_CHILD;
  6523.          SECOND_TREE.LEFTMOST_CHILD := FIRST_TREE;
  6524.          return SECOND_TREE;
  6525.       end if;
  6526.    end ADD;
  6527.  
  6528.  
  6529.    function SYNCHRONIZED_DOUBLE_ADD_WITH_CARRY 
  6530.                                (COMPLETE_SUBFOREST : in PRIORITY_QUEUE_NODE_POINTER;
  6531.                                 QUEUE              : in PRIORITY_QUEUE_NODE_POINTER;
  6532.                                 STARTING_SIZE      : in NATURAL                     ) return PRIORITY_QUEUE_NODE_POINTER is 
  6533.  
  6534.       -- COMPLETE_SUBFOREST and QUEUE must point to identically sized trees; the subforests of which
  6535.       --   they are the smallest trees are added together, and a pointer to the resulting forest is returned. 
  6536.  
  6537.       COMPLETE_SUBFOREST_POINTER   : PRIORITY_QUEUE_NODE_POINTER := COMPLETE_SUBFOREST.SIBLING;
  6538.       QUEUE_POINTER                : PRIORITY_QUEUE_NODE_POINTER := QUEUE.SIBLING;
  6539.       CARRY                        : PRIORITY_QUEUE_NODE_POINTER := ADD (COMPLETE_SUBFOREST, QUEUE);
  6540.       COMPLETE_SUBFOREST_COUNTER   : NATURAL                     := STARTING_SIZE + 1;     -- <= actually, these could both be
  6541.       QUEUE_COUNTER                : NATURAL;                                              -- <= POSITIVE, but we're eliminating 
  6542.       NEXT_COMPLETE_SUBFOREST_TREE : PRIORITY_QUEUE_NODE_POINTER;                          --    the need for a machine-level
  6543.       NEXT_QUEUE_TREE              : PRIORITY_QUEUE_NODE_POINTER;                          --    type conversion...
  6544.       RESULT                       : PRIORITY_QUEUE_NODE_POINTER;
  6545.       RESULT_POINTER               : PRIORITY_QUEUE_NODE_POINTER;
  6546.  
  6547.    begin
  6548.  
  6549.       if (COMPLETE_SUBFOREST_POINTER /= null) and (QUEUE_POINTER /= null) then
  6550.  
  6551. ADDER:     loop
  6552.  
  6553.             QUEUE_COUNTER := NUMBER_OF_CHILDREN (QUEUE_POINTER);
  6554.  
  6555.             while (COMPLETE_SUBFOREST_COUNTER < QUEUE_COUNTER) loop  
  6556.                NEXT_COMPLETE_SUBFOREST_TREE := COMPLETE_SUBFOREST_POINTER.SIBLING;            -- span the gap,  
  6557.                CARRY := ADD (COMPLETE_SUBFOREST_POINTER, CARRY);                              -- collapsing a
  6558.                COMPLETE_SUBFOREST_POINTER := NEXT_COMPLETE_SUBFOREST_TREE;                    -- prefix of the 
  6559.                exit ADDER when (COMPLETE_SUBFOREST_POINTER = null);                           -- complete subforest
  6560.                COMPLETE_SUBFOREST_COUNTER := COMPLETE_SUBFOREST_COUNTER + 1;                  -- into CARRY...
  6561.             end loop;
  6562.  
  6563.             loop
  6564.  
  6565.                if (RESULT /= null) then
  6566.                   RESULT_POINTER.SIBLING := CARRY;
  6567.                else
  6568.                   RESULT := CARRY;
  6569.                end if;
  6570.                RESULT_POINTER := CARRY;
  6571.  
  6572.                NEXT_QUEUE_TREE := QUEUE_POINTER.SIBLING;
  6573.                NEXT_COMPLETE_SUBFOREST_TREE := COMPLETE_SUBFOREST_POINTER.SIBLING;
  6574.                CARRY := ADD (COMPLETE_SUBFOREST_POINTER, QUEUE_POINTER);                -- traverse the path...
  6575.                QUEUE_POINTER := NEXT_QUEUE_TREE;
  6576.                COMPLETE_SUBFOREST_POINTER := NEXT_COMPLETE_SUBFOREST_TREE;
  6577.  
  6578.                exit ADDER when (COMPLETE_SUBFOREST_POINTER = null) or (QUEUE_POINTER = null);
  6579.  
  6580.                QUEUE_COUNTER := NUMBER_OF_CHILDREN (QUEUE_POINTER);
  6581.                COMPLETE_SUBFOREST_COUNTER := COMPLETE_SUBFOREST_COUNTER + 1;
  6582.  
  6583.                exit when (COMPLETE_SUBFOREST_COUNTER < QUEUE_COUNTER);
  6584.  
  6585.             end loop;
  6586.  
  6587.          end loop ADDER;
  6588.  
  6589.       end if;
  6590.  
  6591.       if (RESULT /= null) then
  6592.          RESULT_POINTER.SIBLING := CARRY;
  6593.       else
  6594.          RESULT := CARRY;
  6595.       end if;
  6596.       
  6597.       if (COMPLETE_SUBFOREST_POINTER = null) then
  6598.          CARRY.SIBLING := QUEUE_POINTER;
  6599.       else
  6600.          CARRY.SIBLING := COMPLETE_SUBFOREST_POINTER;
  6601.       end if;
  6602.  
  6603.       return RESULT;
  6604.  
  6605.    end SYNCHRONIZED_DOUBLE_ADD_WITH_CARRY;
  6606.  
  6607.  
  6608.    procedure REINSERT_CHILDREN (QUEUE       : in out PRIORITY_QUEUE;
  6609.                                 FIRST_CHILD : in     PRIORITY_QUEUE_NODE_POINTER) is
  6610.  
  6611.       TEMPORARY_FOREST : PRIORITY_QUEUE_NODE_POINTER := FIRST_CHILD;
  6612.       PREVIOUS_CHILD   : PRIORITY_QUEUE_NODE_POINTER;
  6613.       NEXT_CHILD       : PRIORITY_QUEUE_NODE_POINTER;
  6614.       TREE_NUMBER      : NATURAL;
  6615.  
  6616.    begin
  6617.  
  6618.       if (TEMPORARY_FOREST /= null) then   -- go through the child list and convert it to a *leftward*-sibling forest...
  6619.          loop
  6620.             NEXT_CHILD := TEMPORARY_FOREST.SIBLING;
  6621.             TEMPORARY_FOREST.SIBLING := PREVIOUS_CHILD;
  6622.             exit when (NEXT_CHILD = null);
  6623.             PREVIOUS_CHILD := TEMPORARY_FOREST;
  6624.             TEMPORARY_FOREST := NEXT_CHILD;
  6625.          end loop;
  6626.       end if; 
  6627.  
  6628.       if (QUEUE = null) then
  6629.  
  6630.          QUEUE := TEMPORARY_FOREST;
  6631.  
  6632.       else
  6633.  
  6634.          NEXT_CHILD := TEMPORARY_FOREST;
  6635.          TREE_NUMBER := NUMBER_OF_CHILDREN (QUEUE);
  6636.  
  6637.          for SKIPPED_TREE in 2..TREE_NUMBER loop    -- synchronize the two queues...
  6638.             PREVIOUS_CHILD := NEXT_CHILD;
  6639.             NEXT_CHILD := NEXT_CHILD.SIBLING;
  6640.             exit when (NEXT_CHILD = null);
  6641.          end loop;
  6642.  
  6643.          if (NEXT_CHILD = null) then                -- concatenate the queues; no addition necessary!!
  6644.             PREVIOUS_CHILD.SIBLING := QUEUE;
  6645.             QUEUE := TEMPORARY_FOREST;
  6646.          elsif (TREE_NUMBER = 1) then
  6647.             QUEUE := SYNCHRONIZED_DOUBLE_ADD_WITH_CARRY (TEMPORARY_FOREST, QUEUE, 1);
  6648.          else
  6649.             PREVIOUS_CHILD.SIBLING := SYNCHRONIZED_DOUBLE_ADD_WITH_CARRY (NEXT_CHILD, QUEUE, TREE_NUMBER);
  6650.             QUEUE := TEMPORARY_FOREST;
  6651.          end if;
  6652.  
  6653.       end if;
  6654.  
  6655.    end REINSERT_CHILDREN;
  6656.  
  6657.  
  6658.    procedure PULL_OUT_HIGHEST_PRIORITY_OBJECT (MAXIMUM_PRIORITY_OBJECT : in out PRIORITY_QUEUE_NODE_POINTER;
  6659.                                                QUEUE                   : in out PRIORITY_QUEUE               ) is
  6660.  
  6661.       TREE_PRECEDING_CURRENT_OBJECT   : PRIORITY_QUEUE_NODE_POINTER;
  6662.       CURRENT_LOCATION                : PRIORITY_QUEUE_NODE_POINTER;
  6663.       TREE_PRECEDING_CURRENT_LOCATION : PRIORITY_QUEUE_NODE_POINTER;
  6664.  
  6665.    begin
  6666.  
  6667.       if (QUEUE = null) then
  6668.          raise No_Items_Currently_Exist_In_This_Empty_Priority_Queue;
  6669.       end if;
  6670.  
  6671.       MAXIMUM_PRIORITY_OBJECT := QUEUE;
  6672.       CURRENT_LOCATION := QUEUE.SIBLING;
  6673.       while (CURRENT_LOCATION /= null) loop
  6674.          if (MAXIMUM_PRIORITY_OBJECT.ENTITY_PRIORITY < CURRENT_LOCATION.ENTITY_PRIORITY) then
  6675.             MAXIMUM_PRIORITY_OBJECT := CURRENT_LOCATION;
  6676.             TREE_PRECEDING_CURRENT_OBJECT := TREE_PRECEDING_CURRENT_LOCATION;
  6677.          end if;
  6678.          TREE_PRECEDING_CURRENT_LOCATION := CURRENT_LOCATION;
  6679.          CURRENT_LOCATION := CURRENT_LOCATION.SIBLING;
  6680.       end loop;
  6681.  
  6682.       if (TREE_PRECEDING_CURRENT_OBJECT = null) then
  6683.          QUEUE := MAXIMUM_PRIORITY_OBJECT.SIBLING;
  6684.       else
  6685.          TREE_PRECEDING_CURRENT_OBJECT.SIBLING := MAXIMUM_PRIORITY_OBJECT.SIBLING;
  6686.       end if;
  6687.  
  6688.       REINSERT_CHILDREN (QUEUE, MAXIMUM_PRIORITY_OBJECT.LEFTMOST_CHILD);
  6689.  
  6690.    end PULL_OUT_HIGHEST_PRIORITY_OBJECT;
  6691.  
  6692.  
  6693.    procedure ANNIHILATE is new UNCHECKED_DEALLOCATION (PRIORITY_QUEUE_NODE, PRIORITY_QUEUE_NODE_POINTER);
  6694.  
  6695.  
  6696.    procedure REMOVE_HIGHEST_PRIORITY_OBJECT (HIGHEST_PRIORITY_OBJECT : in out ENQUEUED_OBJECT;
  6697.                                              QUEUE                   : in out PRIORITY_QUEUE) is
  6698.  
  6699.       -- Works in O (log n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  6700.       -- Raises No_Items_Currently_Exist_In_This_Empty_Priority_Queue if the QUEUE is EMPTY.
  6701.  
  6702.       MAXIMUM_PRIORITY_OBJECT : PRIORITY_QUEUE_NODE_POINTER;
  6703.  
  6704.    begin
  6705.       PULL_OUT_HIGHEST_PRIORITY_OBJECT (MAXIMUM_PRIORITY_OBJECT, QUEUE);
  6706.       ASSIGN (HIGHEST_PRIORITY_OBJECT, MAXIMUM_PRIORITY_OBJECT.ENQUEUED_ENTITY);
  6707.       DESTROY (MAXIMUM_PRIORITY_OBJECT.ENQUEUED_ENTITY);
  6708.       ANNIHILATE (MAXIMUM_PRIORITY_OBJECT); 
  6709.    end REMOVE_HIGHEST_PRIORITY_OBJECT;
  6710.  
  6711.  
  6712.    procedure REMOVE_HIGHEST_PRIORITY_OBJECT (HIGHEST_PRIORITY_OBJECT : in out ENQUEUED_OBJECT;
  6713.                                              PRIORITY_OF_THE_OBJECT  :    out PRIORITY_VALUE;
  6714.                                              QUEUE                   : in out PRIORITY_QUEUE) is
  6715.  
  6716.       -- Works in O (log n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  6717.       -- Raises No_Items_Currently_Exist_In_This_Empty_Priority_Queue if the QUEUE is EMPTY.
  6718.  
  6719.       MAXIMUM_PRIORITY_OBJECT : PRIORITY_QUEUE_NODE_POINTER;
  6720.  
  6721.    begin
  6722.       PULL_OUT_HIGHEST_PRIORITY_OBJECT (MAXIMUM_PRIORITY_OBJECT, QUEUE);
  6723.       ASSIGN (HIGHEST_PRIORITY_OBJECT, MAXIMUM_PRIORITY_OBJECT.ENQUEUED_ENTITY);
  6724.       PRIORITY_OF_THE_OBJECT := MAXIMUM_PRIORITY_OBJECT.ENTITY_PRIORITY;
  6725.       DESTROY (MAXIMUM_PRIORITY_OBJECT.ENQUEUED_ENTITY);
  6726.       ANNIHILATE (MAXIMUM_PRIORITY_OBJECT);
  6727.    end REMOVE_HIGHEST_PRIORITY_OBJECT;
  6728.  
  6729.  
  6730.    procedure INSERT_ITEM (QUEUE    : in out PRIORITY_QUEUE;
  6731.                           ITEM     : in out PRIORITY_QUEUE_NODE_POINTER) is
  6732.  
  6733.    begin
  6734.       if (QUEUE = null) then    -- the new item becomes the only tree in the forest
  6735.          QUEUE := ITEM;
  6736.       elsif (QUEUE.LEFTMOST_CHILD /= null) then    -- just insert the new smallest tree directly into the forest...
  6737.          ITEM.SIBLING := QUEUE;
  6738.          QUEUE := ITEM;
  6739.       else 
  6740.          ADD_WITH_CARRY (QUEUE, ITEM);   
  6741.       end if;
  6742.    end INSERT_ITEM;
  6743.  
  6744.  
  6745.    procedure DELETE_ITEM (QUEUE    : in out PRIORITY_QUEUE;
  6746.                           OBJECT   : in     ENQUEUED_OBJECT;
  6747.                           PRIORITY : in     PRIORITY_VALUE) is
  6748.  
  6749.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  6750.       --
  6751.       -- If multiple occurrences of the specified OBJECT and PRIORITY exist, the first 
  6752.       --   such occurrence found will be deleted, and all others will be left undisturbed.
  6753.       --   PURGE_ITEM should be used if you wish to eliminate all such occurrences. 
  6754.       --
  6755.       -- If no occurrences of the specified OBJECT and PRIORITY exist, and the queue is 
  6756.       --   not empty, raises Requested_Item_Does_Not_Exist_In_This_Priority_Queue.
  6757.       --
  6758.       -- If the QUEUE is EMPTY, raises No_Items_Currently_Exist_In_This_Empty_Priority_Queue.
  6759.  
  6760.  
  6761.       DELETE_LOCATION    : PRIORITY_QUEUE_NODE_POINTER;
  6762.       PREVIOUS_TREE      : PRIORITY_QUEUE_NODE_POINTER;
  6763.       CURRENT_TREE       : PRIORITY_QUEUE_NODE_POINTER := QUEUE; 
  6764.  
  6765.       procedure LOCATE_AND_DELETE (SUBSTRUCTURE : in PRIORITY_QUEUE_NODE_POINTER) is
  6766.  
  6767.       begin
  6768.          if (SUBSTRUCTURE /= null) then
  6769.             if (OBJECT = SUBSTRUCTURE.ENQUEUED_ENTITY) and (PRIORITY = SUBSTRUCTURE.ENTITY_PRIORITY) then   -- we found it!!
  6770.  
  6771.                DELETE_LOCATION := SUBSTRUCTURE;
  6772.  
  6773.                if (CURRENT_TREE = QUEUE) then
  6774.                   QUEUE := QUEUE.SIBLING;
  6775.                else
  6776.                   PREVIOUS_TREE.SIBLING := CURRENT_TREE.SIBLING;
  6777.                end if;
  6778.  
  6779.                if (DELETE_LOCATION.LEFTMOST_CHILD /= null) then
  6780.                   REINSERT_CHILDREN (QUEUE, DELETE_LOCATION.LEFTMOST_CHILD);    -- this pointer gets blown away later...
  6781.                end if;
  6782.  
  6783.                if (DELETE_LOCATION.SIBLING /= null) then
  6784.                   REINSERT_CHILDREN (QUEUE, DELETE_LOCATION.SIBLING);           -- and so does this one. 
  6785.                end if;
  6786.  
  6787.             else   
  6788.  
  6789.                LOCATE_AND_DELETE (SUBSTRUCTURE.LEFTMOST_CHILD);      -- look for the desired item...
  6790.  
  6791.                if (DELETE_LOCATION = null) then                      -- still looking...
  6792.                   LOCATE_AND_DELETE (SUBSTRUCTURE.SIBLING);     
  6793.                end if;
  6794.  
  6795.                if (DELETE_LOCATION /= null) then   -- we found it; start cutting subtrees...
  6796.  
  6797.                   if (SUBSTRUCTURE.LEFTMOST_CHILD /= null) then                   -- cut the kids...
  6798.                      if (SUBSTRUCTURE.LEFTMOST_CHILD /= DELETE_LOCATION) then
  6799.                         REINSERT_CHILDREN (QUEUE, SUBSTRUCTURE.LEFTMOST_CHILD);
  6800.                      end if;
  6801.                      SUBSTRUCTURE.LEFTMOST_CHILD := null;
  6802.                   end if;
  6803.  
  6804.                   if (SUBSTRUCTURE.SIBLING /= null) then                          -- cut the rightward siblings...
  6805.                      if (SUBSTRUCTURE.SIBLING /= DELETE_LOCATION) then
  6806.                         REINSERT_CHILDREN (QUEUE, SUBSTRUCTURE.SIBLING);
  6807.                      end if;
  6808.                      SUBSTRUCTURE.SIBLING := null;
  6809.                   end if;
  6810.  
  6811.                end if;
  6812.  
  6813.             end if;
  6814.          end if;
  6815.       end LOCATE_AND_DELETE;
  6816.  
  6817.    begin
  6818.  
  6819.       if (QUEUE = null) then
  6820.  
  6821.          raise No_Items_Currently_Exist_In_This_Empty_Priority_Queue;
  6822.  
  6823.       else
  6824.  
  6825.          loop     -- over all trees in the queue...
  6826.  
  6827.             if (OBJECT = CURRENT_TREE.ENQUEUED_ENTITY) and (PRIORITY = CURRENT_TREE.ENTITY_PRIORITY) then   -- success!!
  6828.  
  6829.                DELETE_LOCATION := CURRENT_TREE;
  6830.  
  6831.                if (CURRENT_TREE = QUEUE) then
  6832.                   QUEUE := QUEUE.SIBLING;
  6833.                else
  6834.                   PREVIOUS_TREE.SIBLING := CURRENT_TREE.SIBLING;
  6835.                end if;
  6836.  
  6837.                if (DELETE_LOCATION.LEFTMOST_CHILD /= null) then
  6838.                   REINSERT_CHILDREN (QUEUE, DELETE_LOCATION.LEFTMOST_CHILD);
  6839.                end if;
  6840.  
  6841.             else
  6842.  
  6843.                LOCATE_AND_DELETE (CURRENT_TREE.LEFTMOST_CHILD);
  6844.  
  6845.                if (DELETE_LOCATION /= null) then                   
  6846.                   if (CURRENT_TREE.LEFTMOST_CHILD /= null) then              -- put the last remaining child up for adoption...
  6847.                      if (CURRENT_TREE.LEFTMOST_CHILD /= DELETE_LOCATION) then    -- unless it's slated for execution.
  6848.                         INSERT_ITEM (QUEUE, CURRENT_TREE.LEFTMOST_CHILD);
  6849.                      end if;
  6850.                      CURRENT_TREE.LEFTMOST_CHILD := null;
  6851.                   end if;
  6852.                   CURRENT_TREE.SIBLING := null;
  6853.                   INSERT_ITEM (QUEUE, CURRENT_TREE);     -- everything except the deleted item is now back in the queue.
  6854.                end if;
  6855.  
  6856.             end if;
  6857.  
  6858.             exit when (DELETE_LOCATION /= null);
  6859.  
  6860.             PREVIOUS_TREE := CURRENT_TREE;
  6861.  
  6862.             CURRENT_TREE := CURRENT_TREE.SIBLING;
  6863.  
  6864.             exit when (CURRENT_TREE = null);  
  6865.  
  6866.          end loop;
  6867.  
  6868.          if (DELETE_LOCATION /= null) then
  6869.             DESTROY (DELETE_LOCATION.ENQUEUED_ENTITY);
  6870.             ANNIHILATE (DELETE_LOCATION);                 -- here is where those two pointers get blown away.
  6871.          else
  6872.             raise Requested_Item_Does_Not_Exist_In_This_Priority_Queue;
  6873.          end if;
  6874.  
  6875.       end if;
  6876.  
  6877.    end DELETE_ITEM;
  6878.  
  6879.  
  6880.    procedure MERGE (TARGET_QUEUE : in out PRIORITY_QUEUE;
  6881.                     SOURCE_QUEUE : in PRIORITY_QUEUE) is
  6882.  
  6883.       -- The objects which were in the SOURCE_QUEUE are merged into the TARGET_QUEUE; the SOURCE_QUEUE
  6884.       --   is left EMPTY.  Works in O (log n) time, where n is the NUMBER_OF_ITEMS in the newly merged queue. 
  6885.  
  6886.       TARGET_QUEUE_POINTER         : PRIORITY_QUEUE_NODE_POINTER := TARGET_QUEUE;
  6887.       SOURCE_QUEUE_POINTER         : PRIORITY_QUEUE_NODE_POINTER := SOURCE_QUEUE;
  6888.       CARRY                        : PRIORITY_QUEUE_NODE_POINTER;
  6889.  
  6890.       NEXT_TARGET_QUEUE_POINTER    : PRIORITY_QUEUE_NODE_POINTER;
  6891.       NEXT_SOURCE_QUEUE_POINTER    : PRIORITY_QUEUE_NODE_POINTER;
  6892.  
  6893.       TARGET_QUEUE_COUNTER         : NATURAL := 0;
  6894.       SOURCE_QUEUE_COUNTER         : NATURAL := 0;
  6895.       CARRY_COUNTER                : NATURAL;    -- actually, this could be a POSITIVE, but we're 
  6896.                                                  --   eliminating the need for a machine-level type conversion.
  6897.  
  6898.       RESULT                       : PRIORITY_QUEUE_NODE_POINTER;
  6899.       RESULT_POINTER               : PRIORITY_QUEUE_NODE_POINTER;
  6900.  
  6901.       procedure STORE_RESULT (INTERMEDIATE_RESULT : in PRIORITY_QUEUE_NODE_POINTER) is
  6902.  
  6903.       begin
  6904.          if (RESULT /= null) then
  6905.             RESULT_POINTER.SIBLING := INTERMEDIATE_RESULT;
  6906.          else
  6907.             RESULT := INTERMEDIATE_RESULT;
  6908.          end if;
  6909.          RESULT_POINTER := INTERMEDIATE_RESULT;
  6910.       end STORE_RESULT;
  6911.  
  6912.       procedure RESOLVE_REMAINS (QUEUE_POINTER : in out PRIORITY_QUEUE_NODE_POINTER; 
  6913.                                  QUEUE_COUNTER : in out NATURAL                      ) is
  6914.  
  6915.          -- QUEUE_POINTER is not null, and QUEUE_COUNTER tells us how many children 
  6916.          --   are in the first tree in the subforest pointed to by QUEUE_POINTER.
  6917.  
  6918.       begin
  6919.          if (CARRY = null) then
  6920.             if (RESULT = null) then 
  6921.                RESULT := QUEUE_POINTER;
  6922.             else
  6923.                RESULT_POINTER.SIBLING := QUEUE_POINTER;
  6924.             end if;
  6925.          elsif (QUEUE_COUNTER < CARRY_COUNTER) then
  6926.             STORE_RESULT (QUEUE_POINTER);
  6927.             RESULT_POINTER.SIBLING := CARRY;
  6928.          elsif (CARRY_COUNTER < QUEUE_COUNTER) then
  6929.             STORE_RESULT (CARRY);
  6930.             RESULT_POINTER.SIBLING := QUEUE_POINTER;
  6931.          else   -- QUEUE_COUNTER = CARRY_COUNTER...
  6932. CLEANUP:    loop
  6933.                NEXT_TARGET_QUEUE_POINTER := QUEUE_POINTER.SIBLING;      -- squeezing a bit more usefulness out of 
  6934.                CARRY := ADD (CARRY, QUEUE_POINTER);                     --    NEXT_TARGET_QUEUE_POINTER, which is
  6935.                exit CLEANUP when (NEXT_TARGET_QUEUE_POINTER = null);    --    otherwise no longer in use at this point...
  6936.                CARRY_COUNTER := QUEUE_COUNTER + 1;
  6937.                QUEUE_POINTER := NEXT_TARGET_QUEUE_POINTER;
  6938.                QUEUE_COUNTER := NUMBER_OF_CHILDREN (QUEUE_POINTER);
  6939.                if (CARRY_COUNTER < QUEUE_COUNTER) then
  6940.                   CARRY.SIBLING := QUEUE_POINTER;
  6941.                   exit CLEANUP;
  6942.                end if;
  6943.             end loop CLEANUP;
  6944.             if (RESULT /= null) then
  6945.                RESULT_POINTER.SIBLING := CARRY;
  6946.             else
  6947.                RESULT := CARRY;
  6948.             end if;
  6949.          end if;   
  6950.       end RESOLVE_REMAINS;
  6951.  
  6952.    begin
  6953.  
  6954.       if (TARGET_QUEUE_POINTER /= null) and (SOURCE_QUEUE_POINTER /= null) then
  6955.  
  6956. ADDER:   loop
  6957.  
  6958.             if (CARRY = null) then
  6959.                if (TARGET_QUEUE_COUNTER < SOURCE_QUEUE_COUNTER) then
  6960.                   STORE_RESULT (TARGET_QUEUE_POINTER);
  6961.                   TARGET_QUEUE_POINTER := TARGET_QUEUE_POINTER.SIBLING;
  6962.                   exit ADDER when (TARGET_QUEUE_POINTER = null);
  6963.                   TARGET_QUEUE_COUNTER := NUMBER_OF_CHILDREN (TARGET_QUEUE_POINTER); 
  6964.                else  -- SOURCE_QUEUE_COUNTER < TARGET_QUEUE_COUNTER...
  6965.                   STORE_RESULT (SOURCE_QUEUE_POINTER);
  6966.                   SOURCE_QUEUE_POINTER := SOURCE_QUEUE_POINTER.SIBLING;
  6967.                   exit ADDER when (SOURCE_QUEUE_POINTER = null);
  6968.                   SOURCE_QUEUE_COUNTER := NUMBER_OF_CHILDREN (SOURCE_QUEUE_POINTER);
  6969.                end if; 
  6970.             else  -- CARRY /= null...
  6971.                if (TARGET_QUEUE_COUNTER = SOURCE_QUEUE_COUNTER) then
  6972.                   STORE_RESULT (CARRY);
  6973.                   NEXT_TARGET_QUEUE_POINTER := TARGET_QUEUE_POINTER.SIBLING;
  6974.                   NEXT_SOURCE_QUEUE_POINTER := SOURCE_QUEUE_POINTER.SIBLING;
  6975.                   CARRY := ADD (TARGET_QUEUE_POINTER, SOURCE_QUEUE_POINTER);
  6976.                   CARRY_COUNTER := TARGET_QUEUE_COUNTER + 1;
  6977.                   TARGET_QUEUE_POINTER := NEXT_TARGET_QUEUE_POINTER;
  6978.                   SOURCE_QUEUE_POINTER := NEXT_SOURCE_QUEUE_POINTER;
  6979.                   if (TARGET_QUEUE_POINTER /= null) then
  6980.                      TARGET_QUEUE_COUNTER := NUMBER_OF_CHILDREN (TARGET_QUEUE_POINTER);
  6981.                   end if;
  6982.                   if (SOURCE_QUEUE_POINTER /= null) then
  6983.                      SOURCE_QUEUE_COUNTER := NUMBER_OF_CHILDREN (SOURCE_QUEUE_POINTER);
  6984.                   end if;
  6985.                   exit ADDER when (TARGET_QUEUE_POINTER = null) or (SOURCE_QUEUE_POINTER = null);
  6986.                elsif (TARGET_QUEUE_COUNTER < SOURCE_QUEUE_COUNTER) then
  6987.                   if (TARGET_QUEUE_COUNTER = CARRY_COUNTER) then
  6988.                      NEXT_TARGET_QUEUE_POINTER := TARGET_QUEUE_POINTER.SIBLING;
  6989.                      CARRY := ADD (TARGET_QUEUE_POINTER, CARRY);
  6990.                      CARRY_COUNTER := TARGET_QUEUE_COUNTER + 1;
  6991.                      TARGET_QUEUE_POINTER := NEXT_TARGET_QUEUE_POINTER;
  6992.                   else   -- CARRY_COUNTER < TARGET_QUEUE_COUNTER...
  6993.                      STORE_RESULT (CARRY);
  6994.                      RESULT_POINTER.SIBLING := TARGET_QUEUE_POINTER;
  6995.                      RESULT_POINTER := TARGET_QUEUE_POINTER;
  6996.                      TARGET_QUEUE_POINTER := TARGET_QUEUE_POINTER.SIBLING;
  6997.                   end if; 
  6998.                   exit ADDER when (TARGET_QUEUE_POINTER = null);
  6999.                   TARGET_QUEUE_COUNTER := NUMBER_OF_CHILDREN (TARGET_QUEUE_POINTER);
  7000.                else  -- SOURCE_QUEUE_COUNTER < TARGET_QUEUE_COUNTER...
  7001.                   if (SOURCE_QUEUE_COUNTER = CARRY_COUNTER) then
  7002.                      NEXT_SOURCE_QUEUE_POINTER := SOURCE_QUEUE_POINTER.SIBLING;
  7003.                      CARRY := ADD (SOURCE_QUEUE_POINTER, CARRY);
  7004.                      CARRY_COUNTER := SOURCE_QUEUE_COUNTER + 1;
  7005.                      SOURCE_QUEUE_POINTER := NEXT_SOURCE_QUEUE_POINTER;
  7006.                   else   -- CARRY_COUNTER < SOURCE_QUEUE_COUNTER...
  7007.                      STORE_RESULT (CARRY);
  7008.                      RESULT_POINTER.SIBLING := SOURCE_QUEUE_POINTER;
  7009.                      RESULT_POINTER := SOURCE_QUEUE_POINTER;
  7010.                      SOURCE_QUEUE_POINTER := SOURCE_QUEUE_POINTER.SIBLING;
  7011.                   end if; 
  7012.                   exit ADDER when (SOURCE_QUEUE_POINTER = null);
  7013.                   SOURCE_QUEUE_COUNTER := NUMBER_OF_CHILDREN (SOURCE_QUEUE_POINTER);
  7014.                end if;
  7015.             end if; 
  7016.          end loop ADDER;
  7017.       end if;
  7018.                  
  7019.       if (TARGET_QUEUE_POINTER = null) and (SOURCE_QUEUE_POINTER /= null) then
  7020.          RESOLVE_REMAINS (SOURCE_QUEUE_POINTER, SOURCE_QUEUE_COUNTER);
  7021.       elsif (SOURCE_QUEUE_POINTER = null) and (TARGET_QUEUE_POINTER /= null) then
  7022.          RESOLVE_REMAINS (TARGET_QUEUE_POINTER, TARGET_QUEUE_COUNTER);
  7023.       elsif (RESULT /= null) then
  7024.          RESULT_POINTER.SIBLING := CARRY;
  7025.       else
  7026.          RESULT := CARRY;
  7027.       end if;
  7028.  
  7029.       TARGET_QUEUE := RESULT;
  7030.  
  7031.    end MERGE;
  7032.  
  7033.  
  7034.    generic
  7035.  
  7036.       with function TO_BE_PURGED (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is <>;
  7037.  
  7038.       with function OK_TO_DESCEND (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is <>;
  7039.  
  7040.    procedure PURGE_QUEUE (QUEUE   : in out PRIORITY_QUEUE);
  7041.  
  7042.    procedure PURGE_QUEUE (QUEUE   : in out PRIORITY_QUEUE) is
  7043.  
  7044.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  7045.       --
  7046.       -- Will terminate normally, even if the QUEUE was already EMPTY...
  7047.  
  7048.       PREVIOUS_TREE : PRIORITY_QUEUE_NODE_POINTER;
  7049.       CURRENT_TREE  : PRIORITY_QUEUE_NODE_POINTER := QUEUE; 
  7050.       NEXT_TREE     : PRIORITY_QUEUE_NODE_POINTER;
  7051.       SUBTREE_HIT   : BOOLEAN;
  7052.       ROOT_HIT      : BOOLEAN;
  7053.       DEBRIS        : PRIORITY_QUEUE;
  7054.  
  7055.       procedure PURGE_SUBTREE (SUBSTRUCTURE : in out PRIORITY_QUEUE_NODE_POINTER) is
  7056.  
  7057.       begin
  7058.          if (SUBSTRUCTURE /= null) and then OK_TO_DESCEND (SUBSTRUCTURE) then
  7059.             PURGE_SUBTREE (SUBSTRUCTURE.LEFTMOST_CHILD);
  7060.             PURGE_SUBTREE (SUBSTRUCTURE.SIBLING);
  7061.             if TO_BE_PURGED (SUBSTRUCTURE) then
  7062.                if not SUBTREE_HIT then
  7063.                   SUBTREE_HIT := True;
  7064.                   REINSERT_CHILDREN (DEBRIS, SUBSTRUCTURE.LEFTMOST_CHILD);
  7065.                   REINSERT_CHILDREN (DEBRIS, SUBSTRUCTURE.SIBLING);
  7066.                 end if;
  7067.                DESTROY (SUBSTRUCTURE.ENQUEUED_ENTITY);
  7068.                ANNIHILATE (SUBSTRUCTURE);
  7069.             elsif SUBTREE_HIT then
  7070.                INSERT_ITEM (DEBRIS, SUBSTRUCTURE);
  7071.                SUBSTRUCTURE := null;
  7072.             end if;
  7073.          end if;
  7074.       end PURGE_SUBTREE;
  7075.  
  7076.    begin
  7077.       while (CURRENT_TREE /= null) loop     -- over all trees in the queue...
  7078.  
  7079.          ROOT_HIT := TO_BE_PURGED (CURRENT_TREE);
  7080.  
  7081.          SUBTREE_HIT := False;
  7082.  
  7083.          PURGE_SUBTREE (CURRENT_TREE.LEFTMOST_CHILD);
  7084.  
  7085.          if ROOT_HIT or SUBTREE_HIT then   
  7086.  
  7087.             if (CURRENT_TREE = QUEUE) then
  7088.                QUEUE := QUEUE.SIBLING;
  7089.                NEXT_TREE := QUEUE;
  7090.             else
  7091.                PREVIOUS_TREE.SIBLING := CURRENT_TREE.SIBLING;
  7092.                NEXT_TREE := PREVIOUS_TREE.SIBLING;
  7093.             end if;
  7094.  
  7095.             if ROOT_HIT then
  7096.                if (CURRENT_TREE.LEFTMOST_CHILD /= null) then
  7097.                   REINSERT_CHILDREN (DEBRIS, CURRENT_TREE.LEFTMOST_CHILD);
  7098.                end if;
  7099.                DESTROY (CURRENT_TREE.ENQUEUED_ENTITY);
  7100.                ANNIHILATE (CURRENT_TREE);
  7101.             else
  7102.                CURRENT_TREE.SIBLING := null;
  7103.                INSERT_ITEM (DEBRIS, CURRENT_TREE);
  7104.             end if;
  7105.  
  7106.             CURRENT_TREE := NEXT_TREE;
  7107.  
  7108.          else
  7109.  
  7110.             PREVIOUS_TREE := CURRENT_TREE;
  7111.  
  7112.             CURRENT_TREE := CURRENT_TREE.SIBLING;
  7113.  
  7114.          end if;
  7115.  
  7116.       end loop;
  7117.  
  7118.       MERGE (QUEUE, DEBRIS);
  7119.  
  7120.    end PURGE_QUEUE;
  7121.  
  7122.  
  7123.    procedure PURGE_ITEM (QUEUE   : in out PRIORITY_QUEUE;
  7124.                          OBJECT  : in     ENQUEUED_OBJECT) is
  7125.  
  7126.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  7127.       --
  7128.       -- Will terminate normally, even if the QUEUE was already EMPTY...
  7129.  
  7130.       function TO_BE_PURGED (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7131.  
  7132.       begin
  7133.          return (NODE.ENQUEUED_ENTITY = OBJECT);
  7134.       end TO_BE_PURGED;
  7135.  
  7136.       function OK_TO_DESCEND (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7137.  
  7138.       begin
  7139.          return True;
  7140.       end OK_TO_DESCEND;
  7141.  
  7142.       procedure PURGE is new PURGE_QUEUE;
  7143.  
  7144.    begin
  7145.       PURGE (QUEUE);
  7146.    end PURGE_ITEM;
  7147.  
  7148.  
  7149.    procedure PURGE_ITEM (QUEUE    : in out PRIORITY_QUEUE;
  7150.                          OBJECT   : in     ENQUEUED_OBJECT;
  7151.                          PRIORITY : in     PRIORITY_VALUE) is
  7152.  
  7153.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  7154.       --
  7155.       -- Will terminate normally, even if the QUEUE was already EMPTY... 
  7156.  
  7157.       function TO_BE_PURGED (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7158.  
  7159.       begin
  7160.          return ( (NODE.ENTITY_PRIORITY = PRIORITY) and then (NODE.ENQUEUED_ENTITY = OBJECT) );
  7161.       end TO_BE_PURGED;
  7162.  
  7163.       function OK_TO_DESCEND (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7164.  
  7165.       begin
  7166.          return ( not (PRIORITY < NODE.ENTITY_PRIORITY) );
  7167.       end OK_TO_DESCEND;
  7168.  
  7169.       procedure PURGE is new PURGE_QUEUE;
  7170.  
  7171.    begin
  7172.       PURGE (QUEUE);
  7173.    end PURGE_ITEM;
  7174.  
  7175.  
  7176.    procedure PURGE_PRIORITY (QUEUE    : in out PRIORITY_QUEUE;
  7177.                              PRIORITY : in     PRIORITY_VALUE) is
  7178.  
  7179.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  7180.       --
  7181.       -- Will terminate normally, even if the QUEUE was already EMPTY... 
  7182.  
  7183.       function TO_BE_PURGED (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7184.  
  7185.       begin
  7186.          return (NODE.ENTITY_PRIORITY = PRIORITY);
  7187.       end TO_BE_PURGED;
  7188.  
  7189.       function OK_TO_DESCEND (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7190.  
  7191.       begin
  7192.          return ( not (PRIORITY < NODE.ENTITY_PRIORITY) );
  7193.       end OK_TO_DESCEND;
  7194.  
  7195.       procedure PURGE is new PURGE_QUEUE;
  7196.  
  7197.    begin
  7198.       PURGE (QUEUE);
  7199.    end PURGE_PRIORITY;
  7200.  
  7201.  
  7202.    procedure PURGE_PRIORITY_RANGE (QUEUE         : in out PRIORITY_QUEUE;
  7203.                                    FROM_PRIORITY : in     PRIORITY_VALUE; 
  7204.                                    TO_PRIORITY   : in     PRIORITY_VALUE) is
  7205.  
  7206.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS originally in the QUEUE.
  7207.       --
  7208.       -- Will terminate normally, even if the QUEUE was already EMPTY...
  7209.  
  7210.       function TO_BE_PURGED (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7211.  
  7212.       begin
  7213.          return ( (NODE.ENTITY_PRIORITY = FROM_PRIORITY) 
  7214.                    or (NODE.ENTITY_PRIORITY = TO_PRIORITY)
  7215.                       or ( (FROM_PRIORITY < NODE.ENTITY_PRIORITY) and (NODE.ENTITY_PRIORITY < TO_PRIORITY) ) );
  7216.       end TO_BE_PURGED;
  7217.  
  7218.       function OK_TO_DESCEND (NODE : in PRIORITY_QUEUE_NODE_POINTER) return BOOLEAN is
  7219.  
  7220.       begin
  7221.          return ( not (TO_PRIORITY < NODE.ENTITY_PRIORITY) );
  7222.       end OK_TO_DESCEND;
  7223.  
  7224.       procedure PURGE is new PURGE_QUEUE;
  7225.  
  7226.    begin
  7227.       PURGE (QUEUE);
  7228.    end PURGE_PRIORITY_RANGE;
  7229.  
  7230.  
  7231.    procedure CHANGE_PRIORITY (QUEUE        : in out PRIORITY_QUEUE;
  7232.                               OBJECT       : in     ENQUEUED_OBJECT;
  7233.                               OLD_PRIORITY : in     PRIORITY_VALUE;
  7234.                               NEW_PRIORITY : in     PRIORITY_VALUE) is
  7235.  
  7236.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS in the QUEUE.
  7237.       -- 
  7238.       -- If multiple occurrences of the specified OBJECT and OLD_PRIORITY exist in the QUEUE, 
  7239.       --   the first such occurrence found will be modified, and all others will be left undisturbed.
  7240.       --
  7241.       -- If no occurrences of the specified OBJECT and OLD_PRIORITY exist in the QUEUE, and the QUEUE is not EMPTY,
  7242.       --   raises Requested_Item_Does_Not_Exist_In_This_Priority_Queue.
  7243.       --
  7244.       -- If the QUEUE is EMPTY, raises No_Items_Currently_Exist_In_This_Empty_Priority_Queue.
  7245.  
  7246.    begin
  7247.       DELETE_ITEM (QUEUE, OBJECT, OLD_PRIORITY);       -- O (n)
  7248.       INSERT_ITEM (QUEUE, OBJECT, NEW_PRIORITY);       -- O (log n)
  7249.    end CHANGE_PRIORITY;
  7250.  
  7251.  
  7252.    function EMPTY (QUEUE : in PRIORITY_QUEUE) return BOOLEAN is
  7253.  
  7254.       -- Works in O (1) time.
  7255.  
  7256.    begin
  7257.       return (QUEUE = null);
  7258.    end EMPTY;
  7259.  
  7260.  
  7261.    function NUMBER_OF_ITEMS (QUEUE : in PRIORITY_QUEUE) return NATURAL is
  7262.  
  7263.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS in the QUEUE.
  7264.  
  7265.       NUMBER_OF_ITEMS_FOUND : NATURAL := 0;
  7266.  
  7267.       procedure FIND_ITEMS (SUBSTRUCTURE : in PRIORITY_QUEUE_NODE_POINTER) is
  7268.  
  7269.       begin
  7270.          if (SUBSTRUCTURE /= null) then
  7271.             NUMBER_OF_ITEMS_FOUND := NUMBER_OF_ITEMS_FOUND + 1;
  7272.             FIND_ITEMS (SUBSTRUCTURE.SIBLING);
  7273.             FIND_ITEMS (SUBSTRUCTURE.LEFTMOST_CHILD);
  7274.          end if;
  7275.       end FIND_ITEMS;
  7276.  
  7277.    begin
  7278.       FIND_ITEMS (QUEUE);
  7279.       return NUMBER_OF_ITEMS_FOUND;
  7280.    end NUMBER_OF_ITEMS;
  7281.  
  7282.  
  7283.    procedure DESTROY (TARGETED_OBJECT : in out PRIORITY_QUEUE) is
  7284.  
  7285.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS in the QUEUE.
  7286.  
  7287.       procedure RECURSIVELY_DESTROY (TARGETED_OBJECT : in out PRIORITY_QUEUE_NODE_POINTER) is
  7288.  
  7289.       begin
  7290.          if (TARGETED_OBJECT /= null) then
  7291.             DESTROY (TARGETED_OBJECT.ENQUEUED_ENTITY);
  7292.             RECURSIVELY_DESTROY (TARGETED_OBJECT.SIBLING);
  7293.             RECURSIVELY_DESTROY (TARGETED_OBJECT.LEFTMOST_CHILD);
  7294.             ANNIHILATE (TARGETED_OBJECT);
  7295.          end if;
  7296.       end RECURSIVELY_DESTROY;
  7297.  
  7298.    begin
  7299.       RECURSIVELY_DESTROY (TARGETED_OBJECT);
  7300.    end DESTROY;
  7301.  
  7302.  
  7303.    procedure ASSIGN (TARGET_OBJECT : in out PRIORITY_QUEUE;
  7304.                      SOURCE_OBJECT : in     PRIORITY_QUEUE) is
  7305.  
  7306.       -- Works in O (n) time, where n is the maximum of the NUMBER_OF_ITEMS to be destroyed in the TARGET_OBJECT
  7307.       --    and the NUMBER_OF_ITEMS in the SOURCE_OBJECT.
  7308.  
  7309.       procedure COPY_STRUCTURE (TARGET_OBJECT : in out PRIORITY_QUEUE_NODE_POINTER;
  7310.                                 SOURCE_OBJECT : in     PRIORITY_QUEUE_NODE_POINTER) is
  7311.  
  7312.       begin
  7313.          if (SOURCE_OBJECT /= null) then
  7314.             TARGET_OBJECT := new PRIORITY_QUEUE_NODE;
  7315.             ASSIGN (TARGET_OBJECT.ENQUEUED_ENTITY, SOURCE_OBJECT.ENQUEUED_ENTITY);
  7316.             TARGET_OBJECT.ENTITY_PRIORITY := SOURCE_OBJECT.ENTITY_PRIORITY;
  7317.             COPY_STRUCTURE (TARGET_OBJECT.SIBLING, SOURCE_OBJECT.SIBLING);
  7318.             COPY_STRUCTURE (TARGET_OBJECT.LEFTMOST_CHILD, SOURCE_OBJECT.LEFTMOST_CHILD);
  7319.          end if;
  7320.       end COPY_STRUCTURE;
  7321.  
  7322.    begin
  7323.       DESTROY (TARGET_OBJECT);
  7324.       COPY_STRUCTURE (TARGET_OBJECT, SOURCE_OBJECT);
  7325.    end ASSIGN;
  7326.  
  7327.  
  7328.    procedure DESTROY (TARGETED_OBJECT : in out POINTER_TO_PRIORITY_QUEUE) is
  7329.  
  7330.       -- Unlike UNCHECKED_DEALLOCATION, this procedure will properly destroy the PRIORITY_QUEUE being pointed to.
  7331.       -- Works in O (n) time, where n is the NUMBER_OF_ITEMS in the PRIORITY_QUEUE being pointed to.
  7332.  
  7333.       procedure ANNIHILATE is new UNCHECKED_DEALLOCATION (PRIORITY_QUEUE, POINTER_TO_PRIORITY_QUEUE);
  7334.  
  7335.    begin
  7336.       if (TARGETED_OBJECT /= null) then
  7337.          DESTROY (TARGETED_OBJECT.all);
  7338.          ANNIHILATE (TARGETED_OBJECT);
  7339.       end if;
  7340.    end DESTROY; 
  7341.  
  7342.  
  7343. end PRIORITIZED_QUEUE;
  7344. --::::::::::
  7345. --qsort.bdy
  7346. --::::::::::
  7347. with TEXT_IO;
  7348. procedure QSORT (A : in out ROW) is
  7349.  
  7350.     procedure QSORT_INTERNAL (L, R : INDEX) is
  7351.  
  7352.         I, J : INDEX;
  7353.         X    : ITEM;
  7354.         TEMP : ITEM;
  7355.  
  7356.     begin
  7357.  
  7358.         I := L;
  7359.         J := R;
  7360.  
  7361.         X := A (INDEX'VAL ((INDEX'POS (L) + INDEX'POS (R)) / 2));
  7362.  
  7363.         MAIN:
  7364.         loop
  7365.  
  7366.             while A (I) < X loop
  7367.                 I := INDEX'SUCC (I);
  7368.             end loop;
  7369.  
  7370.             while X < A (J) loop
  7371.                 J := INDEX'PRED (J);
  7372.             end loop;
  7373.  
  7374.             if I <= J then
  7375.                 TEMP := A(I);
  7376.                 A(I) := A(J);
  7377.                 A(J) := TEMP;
  7378.  
  7379.                 begin
  7380.                     I := INDEX'SUCC (I);
  7381.                     J := INDEX'PRED (J);
  7382.                 exception
  7383.                     when CONSTRAINT_ERROR =>
  7384.                         null; -- necessary to avoid exception raising
  7385.                 end;
  7386.  
  7387.             end if;
  7388.  
  7389.             exit when I > J;
  7390.  
  7391.         end loop MAIN;
  7392.  
  7393.         if L < J then
  7394.             QSORT_INTERNAL (L, J);
  7395.         end if;
  7396.  
  7397.         if I < R then
  7398.             QSORT_INTERNAL (I, R);
  7399.         end if;
  7400.  
  7401.     end QSORT_INTERNAL;
  7402.  
  7403. begin
  7404.  
  7405.     QSORT_INTERNAL (A'FIRST, A'LAST);
  7406.  
  7407. exception
  7408.     when others =>
  7409.         TEXT_IO.PUT_LINE ("QSORT: Exception raised");
  7410. end QSORT;
  7411. --::::::::::
  7412. --random.bdy
  7413. --::::::::::
  7414. with CALENDAR;
  7415. package body RANDOM is
  7416.  
  7417.     X : INTEGER;
  7418.     Y : INTEGER;
  7419.     Z : INTEGER;
  7420.  
  7421.     --=============================================================
  7422.     function CONVERT_TO_FLOAT(ITEM : in INTEGER) return FLOAT is
  7423.     -- This function is necessary for some optimizing compilers
  7424.     -- in order to prevent expressions like FLOAT(INTEGER(FLOAT))
  7425.     -- from being optimized away
  7426.     begin
  7427.         return FLOAT(ITEM);
  7428.     end CONVERT_TO_FLOAT;
  7429.  
  7430.     --=============================================================
  7431.     procedure SEED is
  7432.     -- Generate seed values for X, Y, and Z using Package CALENDAR
  7433.         DAY_MONTH : FLOAT;
  7434.         SECONDS   : FLOAT;
  7435.         HUNDREDS  : FLOAT;
  7436.  
  7437.     begin
  7438.         SECONDS := FLOAT(CALENDAR.SECONDS(CALENDAR.CLOCK));
  7439.         HUNDREDS := (SECONDS/2.88) -
  7440.             CONVERT_TO_FLOAT(INTEGER((SECONDS/2.88) - 0.5));
  7441.         DAY_MONTH := FLOAT(CALENDAR.DAY(CALENDAR.CLOCK) *
  7442.             CALENDAR.MONTH(CALENDAR.CLOCK));
  7443.         X := INTEGER(SECONDS/2.88);
  7444.         Y := INTEGER(HUNDREDS * 30000.0);
  7445.         Z := INTEGER(DAY_MONTH/372.0 * SECONDS * 30000.0);
  7446.     end SEED;
  7447.  
  7448.     --=============================================================
  7449.     function NUMBER return FLOAT is
  7450.     --  This rectangular random number routine is adapted from a report
  7451.     --  "A Pseudo-Random Number Generator" by B. A. Wichmann and I. D. Hill
  7452.     --  NPL Report DNACS XX (to be published)
  7453.     --  In this version, it is suitable for machines supporting
  7454.     --  INTEGER at only 16 bits and is portable in Ada
  7455.  
  7456.     W : FLOAT;
  7457.  
  7458.     begin
  7459.     X := 171 * (X mod 177) - 2 * (X / 177);
  7460.     -- Used to be: X := 171 * (X mod 177 - 177) - 2 * (X / 177);
  7461.     if X < 0 then
  7462.         X := X + 30269;
  7463.     end if;
  7464.     Y := 172 * (Y mod 176) - 35 * (Y / 176);
  7465.     if Y < 0 then
  7466.         Y := Y + 30307;
  7467.     end if;
  7468.     Z := 170 * (Z mod 178) - 63 * (Z / 178);
  7469.     if Z < 0 then
  7470.         Z := Z + 30323;
  7471.     end if;
  7472.  
  7473.     W := FLOAT(X) / 30269.0 + FLOAT(Y) / 30307.0 + FLOAT(Z) / 30323.0;
  7474.     return W - CONVERT_TO_FLOAT(INTEGER(W - 0.5));
  7475.     end NUMBER;
  7476.  
  7477. --=============================================================
  7478. begin
  7479.  
  7480.     SEED;
  7481.     -- Initialize random number generator
  7482.  
  7483. end RANDOM;
  7484. --::::::::::
  7485. --scanners.bdy
  7486. --::::::::::
  7487. package body scanners is    --| Scan tokens from strings
  7488.  
  7489. ----------------------------------------------------------------------------
  7490. -- Local function specs:
  7491.  
  7492. function is_Space(C: Character) return boolean;
  7493. --| Return True iff C is a space or tab.
  7494. pragma inline(is_Space);
  7495.  
  7496. ----------------------------------------------------------------------------
  7497.  
  7498. procedure start_Scanner(    --| Initialize a scanner
  7499.     Scanner: in out Scanner_Type;    --| Scanner to be initialized
  7500.     S: in string;            --| String to be scanned
  7501.     Last: in natural            --| Last scannable character in S.
  7502.     )
  7503. is
  7504.  
  7505. begin
  7506.     Scanner.Index := S'First;
  7507.     Scanner.Max_Index := Last;
  7508.     Scanner.First := 1;
  7509.     Scanner.Last := 0;
  7510.     Scanner.Length := 0;
  7511.  
  7512. end start_Scanner;
  7513.  
  7514. ----------------------------------------------------------------------------
  7515.  
  7516. function is_Empty(    --| Return False if Scanner can scan more characters
  7517.     Scanner: in Scanner_Type
  7518.     ) return boolean is
  7519.  
  7520. begin
  7521.     return Scanner.Index > Scanner.Max_Index;
  7522.  
  7523. end is_Empty;
  7524.  
  7525. ----------------------------------------------------------------------------
  7526.  
  7527. function is_Alpha(    --| Check for alphabetic character
  7528.     Scanner: in scanner_Type;
  7529.     S: in string
  7530.     ) return boolean is
  7531.  
  7532. begin
  7533.     return Scanner.Index <= scanner.Max_Index and then 
  7534.        (S(Scanner.Index) in 'a'..'z' or else
  7535.        S(Scanner.Index) in 'A'..'Z');
  7536.  
  7537. end is_Alpha;
  7538.  
  7539. ----------------------------------------------------------------------------
  7540.  
  7541. function is_Digit(    --| Check for start of  unsigned number
  7542.     Scanner: in scanner_Type;
  7543.     S: in string
  7544.     ) return boolean is
  7545.  
  7546. begin
  7547.     return Scanner.Index <= scanner.Max_Index and then 
  7548.            S(Scanner.Index) in '0'..'9';
  7549.  
  7550. end is_Digit;
  7551.  
  7552. ----------------------------------------------------------------------------
  7553.  
  7554. function is_Sign(    --| Check for '+' or '-'
  7555.     Scanner: in scanner_Type;
  7556.     S: in string
  7557.     ) return boolean is
  7558.  
  7559. begin
  7560.     return Scanner.Index <= scanner.Max_Index and then 
  7561.        (S(Scanner.Index) = '+' or else S(Scanner.Index) = '-');
  7562.  
  7563. end is_Sign;
  7564.  
  7565. ----------------------------------------------------------------------------
  7566.  
  7567. function is_Digit_or_Sign(    --| Check for start of optionally signed number
  7568.     Scanner: in scanner_Type;
  7569.     S: in string
  7570.     ) return boolean is
  7571.  
  7572. begin
  7573.     return Scanner.Index <= scanner.Max_Index and then 
  7574.        (S(Scanner.Index) in '0'..'9'
  7575.        or else S(Scanner.Index) = '+' or else S(Scanner.Index) = '-');
  7576.  
  7577. end is_Digit_or_Sign;
  7578.  
  7579.  
  7580. ----------------------------------------------------------------------------
  7581.  
  7582. procedure skip_Blanks(    --| Skip leading blanks in S
  7583.     Scanner: in out Scanner_Type;    --| Scanner to be updated
  7584.     S: in string            --| String being scanned
  7585.     ) is
  7586.  
  7587. begin
  7588.     Scanner.First := Scanner.Index;
  7589.     Scanner.Length := 0;
  7590.     if Scanner.Index <= Scanner.Max_Index then
  7591.       while is_Space(S(Scanner.Index)) loop
  7592.     Scanner.Index := Scanner.Index + 1;
  7593.     exit when Scanner.Index > Scanner.Max_Index;
  7594.       end loop;
  7595.       Scanner.Length := Scanner.Index - Scanner.First;
  7596.     end if;
  7597.  
  7598. end skip_Blanks;
  7599.  
  7600. ----------------------------------------------------------------------------
  7601.  
  7602. procedure trim_blanks(
  7603.     Scanner: in out Scanner_Type;
  7604.     S: in string
  7605.     ) is
  7606. begin
  7607.     while Scanner.First < Scanner.Last and then is_Space(S(Scanner.First)) loop
  7608.     Scanner.First := Scanner.First + 1;
  7609.     end loop;
  7610.     while Scanner.Last >= Scanner.First and then is_Space(S(Scanner.Last)) loop
  7611.     Scanner.Last := Scanner.Last - 1;
  7612.     end loop;
  7613.     Scanner.Length := Scanner.Last - Scanner.First + 1;
  7614.  
  7615. end trim_Blanks;
  7616.  
  7617. ----------------------------------------------------------------------------
  7618.  
  7619. procedure scan_Until(    --| Scan until C is found
  7620.     Scanner: in out Scanner_Type;
  7621.     S: in string;
  7622.     C: in character
  7623.     )
  7624. is
  7625.     Index: natural := Scanner.Index;
  7626.  
  7627. begin
  7628.     Scanner.Length := 0;
  7629.     if Index <= Scanner.Max_Index then
  7630.       while S(Index) /= C loop
  7631.     Index := Index + 1;
  7632.     if Index > Scanner.Max_Index then    -- Didn't find C
  7633.       return;
  7634.     end if;
  7635.       end loop;
  7636.       Scanner.First := Scanner.Index;    -- First character scanned
  7637.       Scanner.Length := Index - Scanner.First;
  7638.       Scanner.Last := Index - 1;
  7639.       Scanner.Index := Index;
  7640.     end if;
  7641.  
  7642. end scan_Until;
  7643.  
  7644. ----------------------------------------------------------------------------
  7645.  
  7646. procedure scan_Word(    --| Scan past a sequence of non-blank characters
  7647.     Scanner: in out Scanner_Type;
  7648.     S: in string
  7649.     ) is
  7650.  
  7651. begin
  7652.     Scanner.First := Scanner.Index;
  7653.     Scanner.Last := Scanner.First - 1;
  7654.     Scanner.Length := 0;
  7655.     if Scanner.Index <= Scanner.Max_Index then
  7656.       while not is_Space(S(Scanner.Index)) loop
  7657.     Scanner.Index := Scanner.Index + 1;
  7658.     exit when Scanner.Index > Scanner.Max_Index;
  7659.       end loop;
  7660.       Scanner.Length := Scanner.Index - Scanner.First;
  7661.       Scanner.Last := Scanner.Index - 1;
  7662.     end if;
  7663.  
  7664. end scan_Word;
  7665.  
  7666. ----------------------------------------------------------------------------
  7667.  
  7668. procedure scan_Number(
  7669.     Scanner: in out scanner_Type;
  7670.     S: in string
  7671.     ) is
  7672.  
  7673. begin
  7674.     Scanner.First := Scanner.Index;
  7675.     if Scanner.Index <= Scanner.Max_Index then
  7676.       if S(Scanner.Index) = '-' or else S(Scanner.Index) = '+' then
  7677.     Scanner.Index := Scanner.Index + 1;
  7678.       end if;
  7679.       while Scanner.Index <= Scanner.Max_Index
  7680.         and then S(Scanner.Index) in '0'..'9'
  7681.       loop
  7682.     Scanner.Index := Scanner.Index + 1;
  7683.       end loop;
  7684.     end if;
  7685.     Scanner.Length := Scanner.Index - Scanner.First;
  7686.     Scanner.Last := Scanner.Index - 1;
  7687.  
  7688. end scan_Number;
  7689.  
  7690. ----------------------------------------------------------------------------
  7691.  
  7692. procedure scan_Delimited(    --| Scan string delimited by a single character
  7693.     Scanner: in out scanner_Type;
  7694.     S: in string
  7695.     )
  7696. is
  7697.     quote: character;
  7698.  
  7699. begin
  7700.     Scanner.First := Scanner.Index;
  7701.     if Scanner.Index <= Scanner.Max_Index then
  7702.     quote := S(Scanner.Index);
  7703.     Scanner.Index := Scanner.Index + 1;
  7704.     Scanner.First := Scanner.Index;
  7705.     while Scanner.Index <= Scanner.Max_Index 
  7706.           and then S(Scanner.Index) /= quote
  7707.     loop
  7708.       Scanner.Index := Scanner.Index + 1;
  7709.     end loop;
  7710.     end if;
  7711.     Scanner.Length := Scanner.Index - Scanner.First;
  7712.     Scanner.Last := Scanner.Index - 1;
  7713.     if Scanner.Index <= Scanner.Max_Index
  7714.     and then S(Scanner.Index) = quote then    -- Null string?
  7715.     Scanner.Index := Scanner.Index + 1;
  7716.     end if;
  7717.  
  7718. end scan_Delimited;
  7719.  
  7720. ----------------------------------------------------------------------------
  7721.  
  7722. procedure scan_Quoted(    --| Scan quoted string
  7723.     Scanner: in out scanner_Type;
  7724.     S: in out string
  7725.     )
  7726. is
  7727.     quote: character;
  7728.     di: natural;
  7729.  
  7730. begin
  7731.     Scanner.First := Scanner.Index;
  7732.     di := Scanner.Index;
  7733.     if Scanner.Index <= Scanner.Max_Index then
  7734.     quote := S(Scanner.Index);
  7735.     Scanner.Index := Scanner.Index + 1;
  7736.     Scanner.First := Scanner.Index;
  7737.     di := scanner.Index;
  7738.     while Scanner.Index <= Scanner.Max_Index loop
  7739.        if S(Scanner.Index) = quote then    -- Closing quote?
  7740.         if Scanner.Index < Scanner.Max_Index
  7741.         and then S(Scanner.Index + 1) = quote then    -- Doubled quote?
  7742.         Scanner.Index := Scanner.Index + 1;    -- skip it
  7743.         else
  7744.         exit;    -- Found closing quote at Scanner.Index
  7745.         end if;
  7746.       end if;
  7747.       S(di) := S(Scanner.Index);
  7748.       Scanner.Index := Scanner.Index + 1;
  7749.       di := di + 1;
  7750.     end loop;
  7751.     end if;
  7752.     Scanner.Length := di - Scanner.First;
  7753.     Scanner.Last := di - 1;
  7754.     Scanner.Index := Scanner.Index + 1;    -- Skip closing quote
  7755.  
  7756. end scan_Quoted;
  7757.  
  7758. ----------------------------------------------------------------------------
  7759. -- Local function bodies:
  7760.  
  7761. function is_Space(C: Character) return boolean is
  7762. --| Return True iff C is a space or tab.
  7763. begin
  7764.     return C = ' ' or else C = ASCII.HT;
  7765.  
  7766. end is_Space;
  7767.  
  7768. ----------------------------------------------------------------------------
  7769.  
  7770. end scanners;
  7771. --::::::::::
  7772. --search.bdy
  7773. --::::::::::
  7774. package body Search_Utilities is
  7775.   Version_Number : constant STRING := "1.1 (MOPR258)";
  7776.  
  7777.   function Version return STRING is
  7778.   begin
  7779.     return Version_Number;
  7780.   end Version;
  7781.  
  7782.   procedure Search (
  7783.     Component                        : in     Component_Type;
  7784.     Search_Array                     : in     Array_Type;
  7785.     Location_Found                   :    out Index_Type;
  7786.     Component_Found                  :    out BOOLEAN;
  7787.     Number_of_Comparisons            :    out Performance_Instrumentation_Type;
  7788.     Order_Strategy                   : in     Data_Order_Type := Not_Ordered;
  7789.     No_Match_Index                   : in     Index_Type     := Index_Type'LAST) is
  7790.  
  7791.     Local_Comparisons : Performance_Instrumentation_Type := 0;
  7792.  
  7793.     -- The procedure below is a utility routine.
  7794.  
  7795.     procedure Update_Performance_Instrumentation (
  7796.       Instrumentation_Count : in out Performance_Instrumentation_Type) is
  7797.     begin
  7798.       -- Bump the counter unless an overflow has occurred.
  7799.  
  7800.       if Instrumentation_Count /= Performance_Instrumentation_Type'FIRST then
  7801.         if Instrumentation_Count /= Performance_Instrumentation_Type'LAST then
  7802.           Instrumentation_Count := Instrumentation_Count + 1;
  7803.         else
  7804.           Instrumentation_Count := Performance_Instrumentation_Type'FIRST;
  7805.         end if;
  7806.       end if;
  7807.     end Update_Performance_Instrumentation;
  7808.  
  7809.     -- The two local procedures below perform two types of searches
  7810.     -- on the array: a binary search (if data is ordered), and
  7811.     -- a sequential search (if data is not ordered).
  7812.  
  7813.     procedure Binary_Search is
  7814.       High : Index_Type range Search_Array'FIRST .. Search_Array'LAST
  7815.         := Search_Array'LAST;
  7816.       Low  : Index_Type range Search_Array'FIRST .. Search_Array'LAST
  7817.         := Search_Array'FIRST;
  7818.       Curr : Index_Type range Search_Array'FIRST .. Search_Array'LAST
  7819.         := Index_Type'VAL ((Index_Type'POS (High) + Index_Type'POS (Low)) / 2);
  7820.     begin
  7821.       while (Search_Array (Curr) /= Component) and (High > Low) loop
  7822.         Update_Performance_Instrumentation (Local_Comparisons);
  7823.  
  7824.         if Search_Array (Curr) < Component then
  7825.           if Curr = Search_Array'LAST then
  7826.             exit;  -- Can't go any further, component not found.
  7827.           else
  7828.             Low := Index_Type'SUCC (Curr);
  7829.           end if;
  7830.         elsif Curr = Search_Array'FIRST then
  7831.           exit;  -- Can't go any further, component not found.
  7832.         else
  7833.           High := Index_Type'PRED (Curr);
  7834.         end if;
  7835.  
  7836.         Curr := Index_Type'VAL ((Index_Type'POS (High) +
  7837.           Index_Type'POS (Low)) / 2);
  7838.       end loop;
  7839.  
  7840.       if Search_Array (Curr) = Component then
  7841.         Location_Found := Curr;
  7842.         Component_Found := TRUE;
  7843.       else
  7844.         Location_Found := No_Match_Index;
  7845.         Component_Found := FALSE;
  7846.       end if;
  7847.     end Binary_Search;
  7848.  
  7849.     -- Sequential_Search will search for the component starting at the
  7850.     -- beginning of the array.  This search technique is used only if
  7851.     -- the user's data is not sorted.
  7852.  
  7853.     procedure Sequential_Search is
  7854.       Index : Index_Type range Search_Array'FIRST .. Search_Array'LAST :=
  7855.         Search_Array'FIRST;
  7856.     begin
  7857.       while (Index /= Search_Array'LAST) and
  7858.             (Search_Array (Index) /= Component) loop
  7859.         Update_Performance_Instrumentation (Local_Comparisons);
  7860.         Index := Index_Type'SUCC (Index);
  7861.       end loop;
  7862.  
  7863.       if Search_Array (Index) = Component then
  7864.         Location_Found := Index;
  7865.         Component_Found := TRUE;
  7866.       else
  7867.         Location_Found := No_Match_Index;
  7868.         Component_Found := FALSE;
  7869.       end if;
  7870.     end Sequential_Search;
  7871.  
  7872.   -- Body of Search follows below.
  7873.  
  7874.   begin
  7875.     -- Check for null array... a special case.
  7876.  
  7877.     if Search_Array'LAST < Search_Array'FIRST then
  7878.       Location_Found := No_Match_Index;
  7879.       Component_Found := FALSE;
  7880.     else
  7881.       case Order_Strategy is
  7882.         when Not_Ordered => Sequential_Search;  -- Search an unordered array.
  7883.         when Ordered     => Binary_Search;      -- Search an ordered array.
  7884.       end case;
  7885.     end if;
  7886.  
  7887.     Number_of_Comparisons := Local_Comparisons;
  7888.   end Search;
  7889.  
  7890.   -- The following overloading of Search is used when instrumentation
  7891.   -- analysis data are not required.
  7892.  
  7893.   procedure Search (
  7894.     Component                  : in     Component_Type;
  7895.     Search_Array               : in     Array_Type;
  7896.     Location_Found             :    out Index_Type;
  7897.     Component_Found            :    out BOOLEAN;
  7898.     Order_Strategy             : in     Data_Order_Type := Not_Ordered;
  7899.     No_Match_Index             : in     Index_Type     := Index_Type'LAST) is
  7900.  
  7901.     Dummy_Comparisons : Performance_Instrumentation_Type;
  7902.   begin
  7903.     Search (Component, Search_Array, Location_Found, Component_Found,
  7904.       Dummy_Comparisons, Order_Strategy, No_Match_Index);
  7905.   end Search;
  7906.  
  7907.   -- The following overloading of Search should be used when only a
  7908.   -- boolean result is desired.
  7909.  
  7910.   function Search (
  7911.     Component                  : in Component_Type;
  7912.     Search_Array               : in Array_Type;
  7913.     Order_Strategy             : in Data_Order_Type := Not_Ordered)
  7914.     return BOOLEAN is
  7915.  
  7916.     Component_Found   : BOOLEAN;
  7917.     Dummy_Location    : Index_Type;
  7918.     Dummy_Comparisons : Performance_Instrumentation_Type;
  7919.   begin
  7920.     Search (Component, Search_Array, Dummy_Location, Component_Found,
  7921.       Dummy_Comparisons, Order_Strategy);
  7922.  
  7923.     return Component_Found;
  7924.   end Search;
  7925.  
  7926.   -- The following overloading of Search should be used when only an
  7927.   -- index result is desired.
  7928.  
  7929.   function Search (
  7930.     Component                  : in Component_Type;
  7931.     Search_Array               : in Array_Type;
  7932.     Order_Strategy             : in Data_Order_Type := Not_Ordered;
  7933.     No_Match_Index             : in Index_Type      := Index_Type'LAST)
  7934.     return Index_Type is
  7935.  
  7936.     Location_Found    : Index_Type;
  7937.     Dummy_Component   : BOOLEAN;
  7938.     Dummy_Comparisons : Performance_Instrumentation_Type;
  7939.   begin
  7940.     Search (Component, Search_Array, Location_Found, Dummy_Component,
  7941.       Dummy_Comparisons, Order_Strategy, No_Match_Index);
  7942.  
  7943.     return Location_Found;
  7944.   end Search;
  7945. end Search_Utilities;
  7946. --::::::::::
  7947. --slist.bdy
  7948. --::::::::::
  7949. with Unchecked_Deallocation;
  7950. package body Singly_Linked_List is
  7951. --------------------------------------------------------------------------
  7952. -- Abstract   : This package provides an abstraction for a singly linked
  7953. --              list.
  7954. --------------------------------------------------------------------------
  7955. -- Assumptions:
  7956. --      The lists being manipulated must be in one of the following states
  7957. --      both before and after execution of any subprogram in the package:
  7958. --              (1) empty-list          -- Head = null, Tail = null,
  7959. --                                         Previous = null, Current = null
  7960. --              (2) beginning-of-list   -- Head /= null, Tail /= null
  7961. --                                         Previous = null, Current = Head
  7962. --              (3) inside-of-list      -- Head /= null, Tail /= null
  7963. --                                         Previous.Next = Current
  7964. --              (4) outside-of-list     -- Head /= null, Tail /= null
  7965. --                                         Previous = null, Current = null
  7966. ----------------------------------------------------------------------
  7967.  
  7968.   function Empty (List : List_Type) return Boolean is
  7969. --------------------------------------------------------------------------
  7970. -- Abstract   : Indicates whether the list contains any elements.
  7971. --------------------------------------------------------------------------
  7972. -- Parameters : LIST - is the list to be queried.
  7973. --------------------------------------------------------------------------
  7974.   begin
  7975.     return (List.Head = null);
  7976.   end Empty;
  7977.  
  7978.   function Null_Node (List : List_Type) return Boolean is
  7979. --------------------------------------------------------------------------
  7980. -- Abstract   : Indicates whether the "current pointer" references an
  7981. --              element in the list.
  7982. --------------------------------------------------------------------------
  7983. -- Parameters : LIST - is the list to be queried.
  7984. --------------------------------------------------------------------------
  7985.   begin
  7986.     return (List.Current = null);
  7987.   end Null_Node;
  7988.  
  7989.   function Head_Node (List : List_Type) return Boolean is
  7990. --------------------------------------------------------------------------
  7991. -- Abstract   : Indicates whether the "current pointer" references the
  7992. --              head of the list.
  7993. --------------------------------------------------------------------------
  7994. -- Parameters : LIST - is the list to be queried.
  7995. --------------------------------------------------------------------------
  7996.   begin
  7997.     return (List.Current = List.Head);
  7998.   end Head_Node;
  7999.  
  8000.   function Tail_Node (List : List_Type) return Boolean is
  8001. --------------------------------------------------------------------------
  8002. -- Abstract   : Indicates whether the "current pointer" references the
  8003. --              tail of the list.
  8004. --------------------------------------------------------------------------
  8005. -- Parameters : LIST - is the list to be queried.
  8006. --------------------------------------------------------------------------
  8007.   begin
  8008.     return (List.Current = List.Tail);
  8009.   end Tail_Node;
  8010.  
  8011.   function Current_Element (List : List_Type) return List_Element is
  8012. --------------------------------------------------------------------------
  8013. -- Abstract   : Returns the value of the element referenced by the
  8014. --              "current pointer".
  8015. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  8016. --------------------------------------------------------------------------
  8017. -- Parameters : LIST - is the list to be queried.
  8018. --------------------------------------------------------------------------
  8019.   begin
  8020.     if List.Current = null then
  8021.       raise End_Error;
  8022.     else
  8023.       return List.Current.Element;
  8024.     end if;
  8025.   end Current_Element;
  8026.  
  8027.   procedure First (List : in out List_Type) is
  8028. --------------------------------------------------------------------------
  8029. -- Abstract   : Positions the "current pointer" at the head of the list
  8030. --              (even if the list is empty).
  8031. --------------------------------------------------------------------------
  8032. -- Parameters : LIST - is the list to be modified.
  8033. --------------------------------------------------------------------------
  8034.   begin
  8035.     List.Previous := null;
  8036.     List.Current := List.Head;
  8037.   end First;
  8038.  
  8039.   procedure Next (List : in out List_Type) is
  8040. --------------------------------------------------------------------------
  8041. -- Abstract   : Positions the "current pointer" at the next element in the
  8042. --              list.  After the last element in the list NULL_NODE(LIST)
  8043. --              becomes true.
  8044. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  8045. --------------------------------------------------------------------------
  8046. -- Parameters : LIST - is the list to be modified.
  8047. --------------------------------------------------------------------------
  8048.   begin
  8049.     if List.Current = null then
  8050.       raise End_Error;
  8051.     else
  8052.       if List.Current = List.Tail then
  8053.         List.Previous := null;
  8054.       else
  8055.         List.Previous := List.Current;
  8056.       end if;
  8057.       List.Current := List.Current.Next;
  8058.     end if;
  8059.   end Next;
  8060.  
  8061.   procedure Insert_After (List : in out List_Type; Element : List_Element) is
  8062. --------------------------------------------------------------------------
  8063. -- Abstract   : Inserts an element after the "current pointer".
  8064. --              If NULL_NODE(LIST) = TRUE the element is appended after
  8065. --              the tail element of the list.
  8066. --------------------------------------------------------------------------
  8067. -- Parameters : LIST    - is the list to be modified.
  8068. --              ELEMENT - is the element to be inserted.
  8069. --------------------------------------------------------------------------
  8070.   begin
  8071.     if List.Current = null then
  8072.       List.Current := List.Tail;
  8073.     end if;
  8074.     if Empty (List) then
  8075.       List.Head := new Node'(Element, null);
  8076.       List.Tail := List.Head;
  8077.       List.Previous := null;
  8078.       List.Current := List.Head;
  8079.     else
  8080.       declare
  8081.         New_Node : Node_Access := new Node'(Element, List.Current.Next);
  8082.       begin
  8083.         if List.Current = List.Tail then
  8084.           List.Tail := New_Node;
  8085.         end if;
  8086.         List.Previous := List.Current;
  8087.         List.Previous.Next := New_Node;
  8088.         List.Current := New_Node;
  8089.       end;
  8090.     end if;
  8091.   end Insert_After;
  8092.  
  8093.   procedure Insert_Before (List    : in out List_Type;
  8094.                            Element : List_Element) is
  8095. --------------------------------------------------------------------------
  8096. -- Abstract   : Inserts an element before the "current pointer".
  8097. --              If NULL_NODE(LIST) = TRUE the element is prepended before
  8098. --              the head element of the list.
  8099. --------------------------------------------------------------------------
  8100. -- Parameters : LIST    - is the list to be modified.
  8101. --              ELEMENT - is the element to be inserted.
  8102. --------------------------------------------------------------------------
  8103.   begin
  8104.     if List.Current = null then
  8105.       List.Current := List.Head;
  8106.     end if;
  8107.     if Empty (List) then
  8108.       List.Head := new Node'(Element, null);
  8109.       List.Tail := List.Head;
  8110.       List.Previous := null;
  8111.       List.Current := List.Head;
  8112.     elsif List.Current = List.Head then
  8113.       List.Head := new Node'(Element, List.Head);
  8114.       List.Previous := null;
  8115.       List.Current := List.Head;
  8116.     else
  8117.       List.Previous.Next := new Node'(Element, List.Current);
  8118.       List.Current := List.Previous.Next;
  8119.     end if;
  8120.   end Insert_Before;
  8121.  
  8122.   procedure Delete_Element (List : in out List_Type) is
  8123. --------------------------------------------------------------------------
  8124. -- Abstract   : Deletes the element referenced by the "current pointer"
  8125. --              from the list.  Upon deletion the "current pointer"
  8126. --              references the element after the deleted element.
  8127. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  8128. --------------------------------------------------------------------------
  8129. -- Parameters : LIST - is the list to be modified.
  8130. --------------------------------------------------------------------------
  8131.  
  8132.     procedure Free is new Unchecked_Deallocation (Node, Node_Access);
  8133.  
  8134.   begin
  8135.     if List.Current = null then
  8136.       raise End_Error;
  8137.     elsif List.Current = List.Head then
  8138.       declare
  8139.         Next_Node : Node_Access := List.Head.Next;
  8140.       begin
  8141.         Free (List.Head);
  8142.         List.Head := Next_Node;
  8143.         if List.Head = null then
  8144.           List.Tail := null;
  8145.         end if;
  8146.         List.Current := List.Head;
  8147.       end;
  8148.     else
  8149.       if List.Current = List.Tail then
  8150.         List.Tail := List.Previous;
  8151.       end if;
  8152.       List.Previous.Next := List.Current.Next;
  8153.       Free (List.Current);
  8154.       List.Current := List.Previous.Next;
  8155.       if List.Current = null then
  8156.         List.Previous := null;
  8157.       end if;
  8158.     end if;
  8159.   end Delete_Element;
  8160.  
  8161.   procedure Modify (List : List_Type) is
  8162. --------------------------------------------------------------------------
  8163. -- Abstract   : Permits modification of the element referenced by the
  8164. --              "current pointer" where the modification doesn't require
  8165. --              external values (e.g. incrementing a field of the element).
  8166. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  8167. --------------------------------------------------------------------------
  8168. -- Parameters : LIST - is the list to be modified.
  8169. --------------------------------------------------------------------------
  8170.   begin
  8171.     if List.Current = null then
  8172.       raise End_Error;
  8173.     else
  8174.       Transformation (List.Current.Element);
  8175.     end if;
  8176.   end Modify;
  8177.  
  8178.   procedure Update (List : List_Type; Information : Update_Information) is
  8179. --------------------------------------------------------------------------
  8180. -- Abstract   : Permits modification of the element referenced by the
  8181. --              "current pointer" where the modification requires
  8182. --              external values (e.g. assigning a value to a field of
  8183. --              the element).
  8184. --              Raises END_ERROR if NULL_NODE(LIST) = TRUE.
  8185. --------------------------------------------------------------------------
  8186. -- Parameters : LIST        - is the list to be modified.
  8187. --              INFORMATION - is the data necessary for the modification.
  8188. --------------------------------------------------------------------------
  8189.   begin
  8190.     if List.Current = null then
  8191.       raise End_Error;
  8192.     else
  8193.       Transformation (List.Current.Element, Information);
  8194.     end if;
  8195.   end Update;
  8196.  
  8197. end Singly_Linked_List;
  8198. --::::::::::
  8199. --sort.bdy
  8200. --::::::::::
  8201. package body Sort_Utilities is
  8202.   Version_Number : constant STRING := "1.3 (FRAY297)";
  8203.  
  8204. --: function Ordered (A : in Array_Type) return BOOLEAN is
  8205. --: begin
  8206. --:   for I in A'FIRST .. Index_Type'PRED (A'LAST) loop
  8207. --:     if A (Index_Type'SUCC (I)) < A (I) then
  8208. --:       return FALSE;
  8209. --:     end if;
  8210. --:   end loop;
  8211. --:   return TRUE;
  8212. --: end Ordered;
  8213.  
  8214. --: function Permutation (A, B : in Array_Type) return BOOLEAN is
  8215. --:   type Mark_Array_Type is array (A'RANGE) of BOOLEAN;
  8216. --:   Mark       : Mark_Array_Type := (others => FALSE);
  8217. --:   Mark_Pos   : Index_Type;
  8218. --:   Not_Marked : BOOLEAN;
  8219. --: begin
  8220. --:   for I in A'RANGE loop
  8221. --:     Not_Marked := TRUE;
  8222. --:     for J in B'RANGE loop
  8223. --:       if Equal (A (I), B (J)) and not Mark (J) then
  8224. --:         Mark_Pos := J;
  8225. --:         exit;
  8226. --:       end if;
  8227. --:     end loop;
  8228. --:     if Not_Marked then
  8229. --:       return FALSE;
  8230. --:     else
  8231. --:       Mark (Mark_Pos) := TRUE;
  8232. --:     end if;
  8233. --:   end loop;
  8234. --:   return Mark = (others => TRUE);
  8235. --: end Permutation;
  8236.  
  8237.   function Version return STRING is
  8238.   begin
  8239.     return Version_Number;
  8240.   end Version;
  8241.  
  8242.   -- The following subprograms are utilities for the sorting
  8243.   -- procedures that follow them.
  8244.  
  8245.   procedure Update_Performance_Instrumentation (
  8246.     Instrumentation_Count : in out Performance_Instrumentation_Type) is
  8247.   begin
  8248.     -- Bump the counter unless an overflow has occurred.
  8249.  
  8250.     if Instrumentation_Count /= Performance_Instrumentation_Type'FIRST then
  8251.       if Instrumentation_Count /= Performance_Instrumentation_Type'LAST then
  8252.         Instrumentation_Count := Instrumentation_Count + 1;
  8253.       else
  8254.         Instrumentation_Count := Performance_Instrumentation_Type'FIRST;
  8255.       end if;
  8256.     end if;
  8257.   end Update_Performance_Instrumentation;
  8258.  
  8259.   procedure Exchange_Array_Components (
  8260.     Sort_Array          : in out Array_Type;
  8261.     Number_of_Exchanges : in out Performance_Instrumentation_Type) is
  8262.  
  8263.     Temporary_Component : constant Component_Type :=
  8264.       Sort_Array (Sort_Array'FIRST);
  8265.   begin
  8266.     Sort_Array (Sort_Array'FIRST) := Sort_Array (Sort_Array'LAST);
  8267.     Sort_Array (Sort_Array'LAST) := Temporary_Component;
  8268.  
  8269.     Update_Performance_Instrumentation (Number_of_Exchanges);
  8270.   end Exchange_Array_Components;
  8271.  
  8272.   -- Procedure Quicksort is the default sort algorithm used. It is
  8273.   -- a non-recursive method of sorting by constantly partitioning the
  8274.   -- array in half and sorting only that half. This algorithm is
  8275.   -- O(NlogN) and is instable.
  8276.  
  8277.   procedure Quicksort (
  8278.     Sort_Array             : in out Array_Type;
  8279.     Number_of_Comparisons,
  8280.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8281.  
  8282.     type Sort_Array_Index_Save_Type is
  8283.       record
  8284.         Left,
  8285.         Right : Index_Type;
  8286.       end record;
  8287.  
  8288.     subtype Stack_Index_Type is NATURAL range 0 .. Sort_Array'LENGTH;
  8289.  
  8290.     type Stack_Array_Type is array (Stack_Index_Type) of
  8291.       Sort_Array_Index_Save_Type;
  8292.  
  8293.     Local_Comparisons,
  8294.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8295.     I, J, L, R          : Index_Type;
  8296.     Temporary_Component : Component_Type;
  8297.     Stack_Pointer       : Stack_Index_Type;
  8298.     Stack_Array         : Stack_Array_Type;
  8299.   begin
  8300.     if Sort_Array'FIRST < Sort_Array'LAST then
  8301.       Stack_Pointer := 1;
  8302.       Stack_Array (1).Left  := Sort_Array'FIRST;
  8303.       Stack_Array (1).Right := Sort_Array'LAST;
  8304.  
  8305.       loop  -- Take top request from stack.
  8306.         L := Stack_Array (Stack_Pointer).Left;
  8307.         R := Stack_Array (Stack_Pointer).Right;
  8308.         Stack_Pointer := Stack_Pointer - 1;
  8309.  
  8310.         loop  -- Split Sort_Array (Sort_Array'FIRST) .. Sort_Array (R).
  8311.           I := L;
  8312.           J := R;
  8313.           Temporary_Component := Sort_Array (Index_Type'VAL (
  8314.             ((Index_Type'POS (L) + Index_Type'POS (R)) / 2)));
  8315.  
  8316.           loop
  8317.             loop
  8318.               Update_Performance_Instrumentation (Local_Comparisons);
  8319.  
  8320.               exit when (not (Sort_Array (I) < Temporary_Component)) or
  8321.                         (I = Sort_Array'LAST);
  8322.  
  8323.               I := Index_Type'SUCC (I);
  8324.             end loop;
  8325.  
  8326.             loop
  8327.               Update_Performance_Instrumentation (Local_Comparisons);
  8328.  
  8329.               exit when (not (Temporary_Component < Sort_Array (J))) or
  8330.                         (J = Sort_Array'FIRST);
  8331.  
  8332.               J := Index_Type'PRED (J);
  8333.             end loop;
  8334.  
  8335.             if I <= J then
  8336.               if I /= J then
  8337.                 Exchange_Array_Components (Sort_Array (I .. J),Local_Exchanges);
  8338.               end if;
  8339.  
  8340.               if I /= Sort_Array'LAST then
  8341.                 I := Index_Type'SUCC (I);
  8342.               end if;
  8343.  
  8344.               if J /= Sort_Array'FIRST then
  8345.                 J := Index_Type'PRED (J);
  8346.               end if;
  8347.             end if;
  8348.  
  8349.             exit when I > J;
  8350.           end loop;
  8351.  
  8352.           if (Index_Type'POS (J) - Index_Type'POS (L)) <
  8353.              (Index_Type'POS (R) - Index_Type'POS (I)) then
  8354.             if I < R then
  8355.               -- Stack request for sorting right partition.
  8356.  
  8357.               Stack_Pointer := Stack_Pointer + 1;
  8358.               Stack_Array (Stack_Pointer).Left  := I;
  8359.               Stack_Array (Stack_Pointer).Right := R;
  8360.             end if;
  8361.  
  8362.             R := J;  -- Continue sorting left partition.
  8363.           else
  8364.             if L < J then
  8365.               -- Stack request for sorting left partition.
  8366.  
  8367.               Stack_Pointer := Stack_Pointer + 1;
  8368.               Stack_Array (Stack_Pointer).Left  := L;
  8369.               Stack_Array (Stack_Pointer).Right := J;
  8370.             end if;
  8371.  
  8372.             L := I;  -- Continue sorting right partition.
  8373.           end if;
  8374.  
  8375.           exit when L >= R;
  8376.         end loop;
  8377.  
  8378.         exit when Stack_Pointer = 0;
  8379.       end loop;
  8380.     end if;
  8381.  
  8382.     Number_of_Comparisons := Local_Comparisons;
  8383.     Number_of_Exchanges   := Local_Exchanges;
  8384.   end Quicksort;
  8385.  
  8386.   -- The following procedure houses a Quicksort that is identical to
  8387.   -- the one above, except that recursion manages the state and paritions
  8388.   -- instead of an explicit stack.
  8389.  
  8390.   procedure Recursive_Quicksort (
  8391.     Sort_Array             : in out Array_Type;
  8392.     Number_of_Comparisons,
  8393.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8394.  
  8395.     Local_Comparisons,
  8396.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8397.  
  8398.     -- The recursive nature of the sorting algorithm is found in
  8399.     -- the procedure below.
  8400.  
  8401.     procedure Recursive_Quick (Sort_Array : in out Array_Type) is
  8402.       I : Index_Type := Sort_Array'FIRST;
  8403.       J : Index_Type := Sort_Array'LAST;
  8404.  
  8405.       -- The partitioning of the array in half is found in the
  8406.       -- procedure below. It is this procedure that really sorts
  8407.       -- the array by making the necessary exchanges.
  8408.  
  8409.       -- This algorithm DEPENDS on the fact that there are two or
  8410.       -- more array components. Singleton or null arrays are special cases
  8411.       -- and should be handled by the outermost level of the
  8412.       -- Quicksort algorithm.
  8413.  
  8414.       procedure Partition is
  8415.         Sort_Array_Mid_Value : constant Component_Type :=
  8416.           Sort_Array (Index_Type'VAL ((Index_Type'POS (I) + Index_Type'POS (J)) / 2));
  8417.       begin
  8418.         loop
  8419.           while (Sort_Array (I) < Sort_Array_Mid_Value) and
  8420.                 (I /= Sort_Array'LAST) loop
  8421.             Update_Performance_Instrumentation (Local_Comparisons);
  8422.  
  8423.             I := Index_Type'SUCC (I);
  8424.           end loop;
  8425.  
  8426.           while (Sort_Array_Mid_Value < Sort_Array (J)) and
  8427.                 (J /= Sort_Array'FIRST) loop
  8428.             Update_Performance_Instrumentation (Local_Comparisons);
  8429.  
  8430.             J := Index_Type'PRED (J);
  8431.           end loop;
  8432.  
  8433.           if I <= J then
  8434.             if I < J then
  8435.               Exchange_Array_Components (Sort_Array (I .. J),Local_Exchanges);
  8436.             end if;
  8437.  
  8438.             if I /= Sort_Array'LAST then
  8439.               I := Index_Type'SUCC (I);
  8440.             end if;
  8441.  
  8442.             if J /= Sort_Array'FIRST then
  8443.               J := Index_Type'PRED (J);
  8444.             end if;
  8445.           end if;
  8446.  
  8447.           exit when (I > J) or
  8448.                     ((I = Sort_Array'LAST) and (J = Sort_Array'FIRST));
  8449.         end loop;
  8450.       end Partition;
  8451.     begin  -- Recursive_Quick
  8452.       Partition;
  8453.  
  8454.       if Sort_Array'FIRST < J then
  8455.         Recursive_Quick (Sort_Array (Sort_Array'FIRST .. J));
  8456.       end if;
  8457.  
  8458.       if I < Sort_Array'LAST then
  8459.         Recursive_Quick (Sort_Array (I .. Sort_Array'LAST));
  8460.       end if;
  8461.     end Recursive_Quick;
  8462.   begin  -- Recursive_Quicksort
  8463.     -- Handle the special cases of singleton and null arrays...
  8464.     -- do nothing.
  8465.  
  8466.     if Sort_Array'FIRST < Sort_Array'LAST then
  8467.       Recursive_Quick (Sort_Array);
  8468.     end if;
  8469.  
  8470.     Number_of_Comparisons := Local_Comparisons;
  8471.     Number_of_Exchanges   := Local_Exchanges;
  8472.   end Recursive_Quicksort;
  8473.  
  8474.   -- A variation on Recursive_Quicksort is found in the procedure below. It
  8475.   -- is good for sorting data that is already ordered, partially ordered,
  8476.   -- or reverse ordered. The algorithm is O(NlogN) and instable. It is
  8477.   -- a combination of Recursive_Quicksort and Bubble_Sort_with_Quick_Exit.
  8478.  
  8479.   procedure Bsort (
  8480.     Sort_Array             : in out Array_Type;
  8481.     Number_of_Comparisons,
  8482.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8483.  
  8484.     Local_Comparisons,
  8485.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8486.  
  8487.     -- The recursive nature of the algorithm is found in the procedure below.
  8488.  
  8489.     procedure Recursive_Bsort (
  8490.       Low_Index,
  8491.       High_Index    : in Index_Type;
  8492.       Mid_Component : in Component_Type) is
  8493.  
  8494.       Flag, Left_Flag, Right_Flag : BOOLEAN;
  8495.       I, J                        : Index_Type;
  8496.       Size                        : NATURAL;
  8497.  
  8498.       -- Sort_Array (Low_Index .. High_Index) are the components to be
  8499.       -- sorted, and Mid_Component is the value of the middle component.
  8500.       -- I and J are used to partition the subfiles so that at any time
  8501.       -- Sort_Array (I) < Mid_Component and (Mid_Component < Sort_Array (J)
  8502.       -- or Mid_Component = Sort_Array (J)). Left_Flag is TRUE whenever
  8503.       -- the left subfile is not in sorted order, and Right_Flag is
  8504.       -- TRUE whenever the right subfile is not in sorted order. Flag is
  8505.       -- FALSE when the partitioning processes are completed.
  8506.     begin
  8507.       if Low_Index < High_Index then
  8508.         Left_Flag  := FALSE;
  8509.         Right_Flag := FALSE;
  8510.         I          := Low_Index;
  8511.         J          := High_Index;
  8512.         Flag       := TRUE;
  8513.  
  8514.         while Flag loop
  8515.           loop
  8516.             Update_Performance_Instrumentation (Local_Comparisons);
  8517.  
  8518.             exit when (Mid_Component < Sort_Array (I)) or
  8519.                       Equal (Mid_Component,Sort_Array (I)) or (I = J);
  8520.  
  8521.             -- Build the left subfile ensuring that the rightmost component
  8522.             -- is always the largest of the subfile.
  8523.  
  8524.             if I /= Low_Index then
  8525.               Update_Performance_Instrumentation (Local_Comparisons);
  8526.  
  8527.               if Sort_Array (I) < Sort_Array (Index_Type'PRED (I)) then
  8528.                 Exchange_Array_Components (
  8529.                   Sort_Array (Index_Type'PRED (I) .. I),Local_Exchanges);
  8530.  
  8531.                 Left_Flag := TRUE;
  8532.               end if;
  8533.             end if;
  8534.  
  8535.             I := Index_Type'SUCC (I);
  8536.           end loop;
  8537.  
  8538.           loop
  8539.             Update_Performance_Instrumentation (Local_Comparisons);
  8540.  
  8541.             exit when (Sort_Array (J) < Mid_Component) or (I = J);
  8542.  
  8543.             -- Build the right subfile ensuring that the leftmost component
  8544.             -- is always the smallest of the subfile.
  8545.  
  8546.             if J /= High_Index then
  8547.               Update_Performance_Instrumentation (Local_Comparisons);
  8548.  
  8549.               if Sort_Array (Index_Type'SUCC (J)) < Sort_Array (J) then
  8550.                 Exchange_Array_Components (
  8551.                   Sort_Array (J .. Index_Type'SUCC (J)),Local_Exchanges);
  8552.  
  8553.                 Right_Flag := TRUE;
  8554.               end if;
  8555.             end if;
  8556.  
  8557.             J := Index_Type'PRED (J);
  8558.           end loop;
  8559.  
  8560.           if I /= J then
  8561.             -- Interchange Sort_Array (I) from the left subfile with
  8562.             -- Sort_Array (J) from the right subfile.
  8563.  
  8564.             Exchange_Array_Components (Sort_Array (I .. J),Local_Exchanges);
  8565.           else  -- I = J
  8566.             -- Partitioning into left and right subfiles has been completed.
  8567.  
  8568.             Update_Performance_Instrumentation (Local_Comparisons);
  8569.  
  8570.             if (Mid_Component < Sort_Array (J)) or
  8571.                Equal (Mid_Component,Sort_Array (J)) then
  8572.               -- Check the right subfile to ensure the first component,
  8573.               -- Sort_Array (J), is the smallest.
  8574.  
  8575.               if J /= Sort_Array'LAST then
  8576.                 Update_Performance_Instrumentation (Local_Comparisons);
  8577.  
  8578.                 if Sort_Array (Index_Type'SUCC (J)) < Sort_Array (J) then
  8579.                   Exchange_Array_Components (
  8580.                     Sort_Array (J .. Index_Type'SUCC (J)),Local_Exchanges);
  8581.  
  8582.                   Right_Flag := TRUE;
  8583.                 end if;
  8584.               end if;
  8585.             else
  8586.               -- Check the left subfile to ensure the last component,
  8587.               -- Sort_Array (Index_Type'PRED (I)), is the largest.
  8588.  
  8589.               if I /= Sort_Array'FIRST then
  8590.                 Update_Performance_Instrumentation (Local_Comparisons);
  8591.  
  8592.                 if Sort_Array (I) < Sort_Array (Index_Type'PRED (I)) then
  8593.                   Exchange_Array_Components (
  8594.                     Sort_Array (Index_Type'PRED (I) .. I),Local_Exchanges);
  8595.  
  8596.                   Left_Flag := TRUE;
  8597.                 end if;
  8598.               end if;
  8599.  
  8600.               if I > Index_Type'SUCC (Sort_Array'FIRST) then
  8601.                 Update_Performance_Instrumentation (Local_Comparisons);
  8602.  
  8603.                 if Sort_Array (Index_Type'PRED (I)) <
  8604.                    Sort_Array (Index_Type'PRED (Index_Type'PRED (I))) then
  8605.                   Exchange_Array_Components (
  8606.                     Sort_Array (Index_Type'PRED (Index_Type'PRED (I)) ..
  8607.                                 Index_Type'PRED (I)),Local_Exchanges);
  8608.                 end if;
  8609.               end if;
  8610.             end if;
  8611.  
  8612.             Flag := FALSE;
  8613.           end if;  -- end of "if I /= J"
  8614.         end loop;  -- end of "while Flag loop"
  8615.  
  8616.         -- Process the left subfile.
  8617.  
  8618.         Size := Index_Type'POS (I) - Index_Type'POS (Low_Index);
  8619.  
  8620.         if Size > 2 then
  8621.           -- Subfile must have at least three components to process and
  8622.           -- not already sorted.
  8623.  
  8624.           if Left_Flag then
  8625.             if Size = 3 then
  8626.               -- Special case of 3 components; place Sort_Array (Low_Index)
  8627.               -- and Sort_Array (Index_Type'SUCC (Low_Index)) in sorted order.
  8628.  
  8629.               Update_Performance_Instrumentation (Local_Comparisons);
  8630.  
  8631.               if Sort_Array (Index_Type'SUCC (Low_Index)) <
  8632.                  Sort_Array (Low_Index) then
  8633.                 Exchange_Array_Components (
  8634.                   Sort_Array (Low_Index .. Index_Type'SUCC (Low_Index)),
  8635.                     Local_Exchanges);
  8636.               end if;
  8637.             else
  8638.               Recursive_Bsort (Low_Index,Index_Type'PRED (Index_Type'PRED (I)),
  8639.                 Sort_Array (Index_Type'VAL (
  8640.                            ((Index_Type'POS (Low_Index) + Index_Type'POS (I)
  8641.                              - 2) / 2)
  8642.                           )));
  8643.             end if;
  8644.           end if;
  8645.         end if;
  8646.  
  8647.         -- Process the right subfile.
  8648.  
  8649.         Size := Index_Type'POS (High_Index) - Index_Type'POS (J) + 1;
  8650.  
  8651.         if Size > 2 then
  8652.           -- Subfile must have at least 3 components to process and not
  8653.           -- already sorted.
  8654.  
  8655.           if Right_Flag then
  8656.             if Size = 3 then
  8657.               -- Special case of 3 components; place
  8658.               -- Sort_Array (Index_Type'SUCC (J)) and
  8659.               -- Sort_Array (Index_Type'SUCC (Index_Type'SUCC (J))) in sorted
  8660.               -- order.
  8661.  
  8662.               Update_Performance_Instrumentation (Local_Comparisons);
  8663.  
  8664.               if Sort_Array (Index_Type'SUCC (Index_Type'SUCC (J))) <
  8665.                  Sort_Array (Index_Type'SUCC (J)) then
  8666.                 Exchange_Array_Components (
  8667.                   Sort_Array (Index_Type'SUCC (J) ..
  8668.                               Index_Type'SUCC (Index_Type'SUCC (J))),
  8669.                               Local_Exchanges);
  8670.               end if;
  8671.             else
  8672.               Recursive_Bsort (Index_Type'SUCC (J),High_Index,
  8673.                 Sort_Array (Index_Type'VAL (
  8674.                            ((Index_Type'POS (J) + Index_Type'POS (High_Index)
  8675.                              + 1) / 2)
  8676.                           )));
  8677.             end if;
  8678.           end if;
  8679.         end if;
  8680.       end if;  -- end of "if M < N then"
  8681.     end Recursive_Bsort;
  8682.   begin  -- Bsort
  8683.     -- Do not bother with singleton and null arrays.
  8684.  
  8685.     if Sort_Array'FIRST < Sort_Array'LAST then
  8686.       Recursive_Bsort (Sort_Array'FIRST,Sort_Array'LAST,
  8687.         Sort_Array (Index_Type'VAL (
  8688.          ((Index_Type'POS (Sort_Array'FIRST) +
  8689.            Index_Type'POS (Sort_Array'LAST)) / 2))));
  8690.     end if;
  8691.  
  8692.     Number_of_Comparisons := Local_Comparisons;
  8693.     Number_of_Exchanges   := Local_Exchanges;
  8694.   end Bsort;
  8695.  
  8696.   -- A bubble sort algorithm is found in the procedure below. The
  8697.   -- algorithm used is a standard bubble sort. This algorithm is
  8698.   -- O(N**2) and is stable.
  8699.  
  8700.   procedure Bubble_Sort (
  8701.     Sort_Array             : in out Array_Type;
  8702.     Number_of_Comparisons,
  8703.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8704.  
  8705.     Local_Comparisons,
  8706.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8707.   begin
  8708.     -- Check for the singleton/null array cases... do nothing.
  8709.  
  8710.     if Sort_Array'FIRST < Sort_Array'LAST then
  8711.       for I in Sort_Array'FIRST .. Index_Type'VAL (Index_Type'POS (Sort_Array'LAST) - 1) loop
  8712.         for J in Sort_Array'FIRST ..
  8713.                  Index_Type'VAL (
  8714.                                  (Index_Type'POS (Sort_Array'LAST)  +
  8715.                                   Index_Type'POS (Sort_Array'FIRST) - 1
  8716.                                  ) -
  8717.                                  Index_Type'POS (I)
  8718.                                 ) loop
  8719.           Update_Performance_Instrumentation (Local_Comparisons);
  8720.  
  8721.           if Sort_Array (Index_Type'SUCC (J)) < Sort_Array (J) then
  8722.             Exchange_Array_Components (Sort_Array (J .. Index_Type'SUCC (J)),
  8723.                                        Local_Exchanges);
  8724.           end if;
  8725.         end loop;
  8726.       end loop;
  8727.     end if;
  8728.  
  8729.     Number_of_Comparisons := Local_Comparisons;
  8730.     Number_of_Exchanges   := Local_Exchanges;
  8731.   end Bubble_Sort;
  8732.  
  8733.   -- A bubble sort algorithm is found in the procedure below. The
  8734.   -- algorithm used is a standard bubble sort with a quick exit. The
  8735.   -- quick exit is taken if the data just happens to be sorted
  8736.   -- in the middle of the process. Thus, this algorithm may be faster
  8737.   -- than O(N**2) for arrays that are already partially ordered.
  8738.  
  8739.   procedure Bubble_Sort_with_Quick_Exit (
  8740.     Sort_Array             : in out Array_Type;
  8741.     Number_of_Comparisons,
  8742.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8743.  
  8744.     Local_Comparisons,
  8745.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8746.     Interchange_Made   : BOOLEAN;
  8747.   begin
  8748.     -- Check for the singleton/null array cases... do nothing.
  8749.  
  8750.     if Sort_Array'FIRST < Sort_Array'LAST then
  8751.       for I in Sort_Array'FIRST .. Index_Type'VAL (
  8752.                Index_Type'POS (Sort_Array'LAST) - 1) loop
  8753.         Interchange_Made := FALSE;
  8754.  
  8755.         for J in Sort_Array'FIRST ..
  8756.                  Index_Type'VAL (
  8757.                                  (Index_Type'POS (Sort_Array'LAST) +
  8758.                                   Index_Type'POS (Sort_Array'FIRST) - 1
  8759.                                  ) -
  8760.                                  Index_Type'POS (I)
  8761.                                 ) loop
  8762.           Update_Performance_Instrumentation (Local_Comparisons);
  8763.  
  8764.           if Sort_Array (Index_Type'SUCC (J)) < Sort_Array (J) then
  8765.             Interchange_Made := TRUE;
  8766.             Exchange_Array_Components (Sort_Array (J .. Index_Type'SUCC (J)),
  8767.                                        Local_Exchanges);
  8768.           end if;
  8769.         end loop;
  8770.  
  8771.         exit when not Interchange_Made;
  8772.       end loop;
  8773.     end if;
  8774.  
  8775.     Number_of_Comparisons := Local_Comparisons;
  8776.     Number_of_Exchanges   := Local_Exchanges;
  8777.   end Bubble_Sort_with_Quick_Exit;
  8778.  
  8779.   -- A straight selection sort follows below. It is O(N**2) and
  8780.   -- is instable.
  8781.  
  8782.   procedure Selection_Sort (
  8783.     Sort_Array             : in out Array_Type;
  8784.     Number_of_Comparisons,
  8785.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8786.  
  8787.     Local_Comparisons,
  8788.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  8789.     Small              : Index_Type;
  8790.   begin
  8791.     -- Check for singelton/null array case... do nothing.
  8792.  
  8793.     if Sort_Array'FIRST < Sort_Array'LAST then
  8794.       for I in Sort_Array'FIRST .. Index_Type'PRED (Sort_Array'LAST) loop
  8795.         Small := I;
  8796.  
  8797.         for J in Index_Type'SUCC (I) .. Sort_Array'LAST loop
  8798.           Update_Performance_Instrumentation (Local_Comparisons);
  8799.  
  8800.           if Sort_Array (J) < Sort_Array (Small) then
  8801.             Small := J;
  8802.           end if;
  8803.         end loop;
  8804.  
  8805.         if I /= Small then
  8806.           Exchange_Array_Components (Sort_Array (I .. Small),Local_Exchanges);
  8807.         end if;
  8808.       end loop;
  8809.     end if;
  8810.  
  8811.     Number_of_Comparisons := Local_Comparisons;
  8812.     Number_of_Exchanges   := Local_Exchanges;
  8813.   end Selection_Sort;
  8814.  
  8815.   -- Heapsort follows below. It is O(NlogN) and is instable.
  8816.  
  8817.   procedure Heapsort (
  8818.     Sort_Array             : in out Array_Type;
  8819.     Number_of_Comparisons,
  8820.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8821.  
  8822.     Local_Comparisons,
  8823.     Local_Exchanges     : Performance_Instrumentation_Type := 0;
  8824.     I,J                 : Index_Type;
  8825.     Temporary_Component : Component_Type;
  8826.   begin
  8827.     -- Check for special array cases: do nothing on singleton/null,
  8828.     -- must handle an array of 2 elements separate since the algorithm
  8829.     -- assumes that Sort_Array'LENGTH >= 3.
  8830.  
  8831.     if Sort_Array'LENGTH = 2 then
  8832.       Update_Performance_Instrumentation (Local_Comparisons);
  8833.  
  8834.       if Sort_Array (Sort_Array'LAST) < Sort_Array (Sort_Array'FIRST) then
  8835.         Exchange_Array_Components (Sort_Array,Local_Exchanges);
  8836.       end if;
  8837.     elsif Sort_Array'FIRST < Sort_Array'LAST then
  8838.       -- Create initial heap.
  8839.  
  8840.       for K in Index_Type'SUCC (Sort_Array'FIRST) .. Sort_Array'LAST loop
  8841.         -- Insert Sort_Array (K) into existing heap of size K-1.
  8842.  
  8843.         I := K;
  8844.         Temporary_Component := Sort_Array (K);
  8845.  
  8846.         -- The complex expression in assigning to J below is necessary
  8847.         -- due to the generic nature of the algorithm. This
  8848.         -- expression is used in other places below too.
  8849.  
  8850.         if Index_Type'POS (I) >= 0 then
  8851.           J := Index_Type'VAL ((Index_Type'POS (I) +
  8852.                Index_Type'POS (Sort_Array'FIRST) - 1) / 2);
  8853.         elsif ((Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1)
  8854.                mod 2) = 0 then
  8855.           J := Index_Type'VAL ((Index_Type'POS (I) +
  8856.                Index_Type'POS (Sort_Array'FIRST) - 1) / 2);
  8857.         else
  8858.           J := Index_Type'VAL ((Index_Type'POS (I) +
  8859.                Index_Type'POS (Sort_Array'FIRST) - 2) / 2);
  8860.         end if;
  8861.  
  8862.         while J >= Sort_Array'FIRST loop
  8863.           Update_Performance_Instrumentation (Local_Comparisons);
  8864.  
  8865.           exit when (Temporary_Component < Sort_Array (J)) or
  8866.             Equal (Temporary_Component,Sort_Array (J));
  8867.  
  8868.           Update_Performance_Instrumentation (Local_Exchanges);
  8869.           Sort_Array (I) := Sort_Array (J);
  8870.           I := J;
  8871.  
  8872.           if Index_Type'POS (I) >= 0 then
  8873.             if (((Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1) / 2) >=
  8874.                 Index_Type'POS (Sort_Array'FIRST)
  8875.                ) and
  8876.                (I /= Sort_Array'FIRST) then
  8877.               J := Index_Type'VAL (
  8878.                      (Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1)
  8879.                      / 2);
  8880.             else
  8881.               exit;  -- Exit while loop.
  8882.             end if;
  8883.           elsif ((Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1)
  8884.                  mod 2) = 0 then
  8885.              if (((Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1) / 2) >=
  8886.                  Index_Type'POS (Sort_Array'FIRST)
  8887.                 ) and
  8888.                 (I /= Sort_Array'FIRST) then
  8889.                J := Index_Type'VAL (
  8890.                       (Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1)
  8891.                       / 2);
  8892.              else
  8893.                exit;  -- Exit while loop.
  8894.              end if;
  8895.            elsif (((Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 1) / 2) >=
  8896.                   Index_Type'POS (Sort_Array'FIRST)
  8897.                  ) and
  8898.                  (I /= Sort_Array'FIRST) then
  8899.                 J := Index_Type'VAL (
  8900.                        (Index_Type'POS (I) + Index_Type'POS (Sort_Array'FIRST) - 2)
  8901.                        / 2);
  8902.            else
  8903.              exit;  -- Exit while loop.
  8904.           end if;
  8905.         end loop;  -- End of while loop.
  8906.  
  8907.         Update_Performance_Instrumentation (Local_Comparisons);
  8908.  
  8909.         if not Equal (Temporary_Component,Sort_Array (I)) then
  8910.           Update_Performance_Instrumentation (Local_Exchanges);
  8911.           Sort_Array (I) := Temporary_Component;
  8912.         end if;
  8913.       end loop;  -- End of for loop.
  8914.  
  8915.       -- We remove Sort_Array (Sort_Array'FIRST) and place it in its
  8916.       -- proper position in the array. We then adjust the heap.
  8917.  
  8918.       for K in reverse Index_Type'SUCC (Sort_Array'FIRST) .. Sort_Array'LAST loop
  8919.         Update_Performance_Instrumentation (Local_Exchanges);
  8920.         Temporary_Component := Sort_Array (K);
  8921.         Sort_Array (K) := Sort_Array (Sort_Array'FIRST);
  8922.  
  8923.         -- Readjust the heap of order K-1. Move Temporary_Component down the
  8924.         -- heap for proper position.
  8925.  
  8926.         I := Sort_Array'FIRST;
  8927.         J := Index_Type'SUCC (I);
  8928.  
  8929.         -- The following if statement can be described as follows:
  8930.         --   if (Sort_Array (Element#2) < Sort_Array (Element#3)) and
  8931.         --      (Position of K's predecessor >= Position of Element#3) then
  8932.         --     J := Position of Element#3;
  8933.         --   end if;
  8934.         -- The complications are due to the generic nature of the
  8935.         -- algorithm.
  8936.  
  8937.         Update_Performance_Instrumentation (Local_Comparisons);
  8938.  
  8939.         if ((Sort_Array (Index_Type'SUCC (Sort_Array'FIRST))) <
  8940.             (Sort_Array (Index_Type'SUCC (Index_Type'SUCC (Sort_Array'FIRST))))
  8941.            ) and
  8942.            (Index_Type'PRED (K) >=
  8943.             Index_Type'SUCC (Index_Type'SUCC (Sort_Array'FIRST))
  8944.            ) then
  8945.           J := Index_Type'SUCC (Index_Type'SUCC (Sort_Array'FIRST));
  8946.         end if;
  8947.  
  8948.         -- J is the larger son of I in the heap of size K-1.
  8949.  
  8950.         while J <= Index_Type'PRED (K) loop
  8951.           Update_Performance_Instrumentation (Local_Comparisons);
  8952.  
  8953.           if (Sort_Array (J) < Temporary_Component) or
  8954.              Equal (Sort_Array (J),Temporary_Component) then
  8955.             exit;  -- exit while loop
  8956.           end if;
  8957.  
  8958.           Update_Performance_Instrumentation (Local_Exchanges);
  8959.           Sort_Array (I) := Sort_Array (J);
  8960.           I := J;
  8961.  
  8962.           if (((Index_Type'POS (I) * 2) - Index_Type'POS (Sort_Array'FIRST) + 1) <=
  8963.               Index_Type'POS (Index_Type'PRED (Sort_Array'LAST))
  8964.              ) and
  8965.              (((Index_Type'POS (I) * 2) - Index_Type'POS (Sort_Array'FIRST) + 1) >=
  8966.               Index_Type'POS (Sort_Array'FIRST)
  8967.              ) then
  8968.             J := Index_Type'VAL (
  8969.                    (Index_Type'POS (I) * 2) - Index_Type'POS (Sort_Array'FIRST) + 1);
  8970.           else
  8971.             exit;  -- Exit while loop.
  8972.           end if;
  8973.  
  8974.           if Index_Type'SUCC (J) <= Index_Type'PRED (K) then
  8975.             Update_Performance_Instrumentation (Local_Comparisons);
  8976.  
  8977.             if Sort_Array (J) < Sort_Array (Index_Type'SUCC (J)) then
  8978.               J := Index_Type'SUCC (J);
  8979.             end if;
  8980.           end if;
  8981.         end loop;  -- End of while loop.
  8982.  
  8983.         Update_Performance_Instrumentation (Local_Exchanges);
  8984.         Sort_Array (I) := Temporary_Component;
  8985.       end loop;  -- End of for loop.
  8986.     end if;
  8987.  
  8988.     Number_of_Comparisons := Local_Comparisons;
  8989.     Number_of_Exchanges   := Local_Exchanges;
  8990.   end Heapsort;
  8991.  
  8992.   -- Simple insertion sort follows below. It is O(N**2), but usually
  8993.   -- better than a bubble sort.
  8994.  
  8995.   procedure Insertion_Sort (
  8996.     Sort_Array             : in out Array_Type;
  8997.     Number_of_Comparisons,
  8998.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  8999.  
  9000.     Local_Comparisons,
  9001.     Local_Exchanges     : Performance_Instrumentation_Type := 0;
  9002.     I                   : Index_Type;
  9003.     Temporary_Component : Component_Type;
  9004.     Found               : BOOLEAN;
  9005.   begin
  9006.     -- Handle special cases of singleton/null arrays...
  9007.     -- do nothing.
  9008.  
  9009.     if Sort_Array'FIRST < Sort_Array'LAST then
  9010.       -- Initially Sort_Array (Sort_Array'FIRST) may be thought of
  9011.       -- as a sorted file of one element. After each repetition of
  9012.       -- the following loop, the elements Sort_Array (Sort_Array'FIRST)
  9013.       -- through Sort_Array (K) are in order.
  9014.  
  9015.       for K in Index_Type'SUCC (Sort_Array'FIRST) .. Sort_Array'LAST loop
  9016.         -- insert Sort_Array (K) into the sorted file
  9017.  
  9018.         Temporary_Component := Sort_Array (K);
  9019.  
  9020.         -- Move down one position all elements "greater" than
  9021.         -- Temporary_Component
  9022.  
  9023.         I := Index_Type'PRED (K);
  9024.         Found := FALSE;
  9025.  
  9026.         while (not Found) loop
  9027.           Update_Performance_Instrumentation (Local_Comparisons);
  9028.  
  9029.           if Temporary_Component < Sort_Array (I) then
  9030.             Update_Performance_Instrumentation (Local_Exchanges);
  9031.             Sort_Array (Index_Type'SUCC (I)) := Sort_Array (I);
  9032.  
  9033.             if I /= Sort_Array'FIRST then
  9034.               I := Index_Type'PRED (I);
  9035.             else
  9036.               exit;  -- Exit while loop.
  9037.             end if;
  9038.           else
  9039.             Found := TRUE;
  9040.           end if;
  9041.         end loop;  -- End of while loop.
  9042.  
  9043.         -- Insert Temporary_Component at proper position.
  9044.  
  9045.         Update_Performance_Instrumentation (Local_Exchanges);
  9046.  
  9047.         if Found then
  9048.           Sort_Array (Index_Type'SUCC (I)) := Temporary_Component;
  9049.         else
  9050.           Sort_Array (Sort_Array'FIRST) := Temporary_Component;
  9051.         end if;
  9052.       end loop;  -- End of for loop.
  9053.     end if;
  9054.  
  9055.     Number_of_Comparisons := Local_Comparisons;
  9056.     Number_of_Exchanges := Local_Exchanges;
  9057.   end Insertion_Sort;
  9058.  
  9059.   -- The straight merge sort procedure below is O(NlogN) and is instable.
  9060.  
  9061.   procedure Merge_Sort (
  9062.     Sort_Array             : in out Array_Type;
  9063.     Number_of_Comparisons,
  9064.     Number_of_Exchanges    :    out Performance_Instrumentation_Type) is
  9065.  
  9066.     Auxiliary_Array    : Array_Type (Sort_Array'FIRST .. Sort_Array'LAST);
  9067.     Lower_Bound1,
  9068.     Lower_Bound2,
  9069.     Upper_Bound1,
  9070.     Upper_Bound2,
  9071.     Auxiliary_Index,
  9072.     I, J               : Index_Type;
  9073.     I_Overflow,
  9074.     J_Overflow,
  9075.     Aux_Overflow       : BOOLEAN;
  9076.     Size               : POSITIVE := 1;  -- Merge files of size 1.
  9077.     Local_Comparisons,
  9078.     Local_Exchanges    : Performance_Instrumentation_Type := 0;
  9079.   begin
  9080.     while Size < Sort_Array'LENGTH loop
  9081.       Lower_Bound1 := Sort_Array'FIRST;
  9082.       Auxiliary_Index := Auxiliary_Array'FIRST;
  9083.  
  9084.       -- Check if there are two files to merge.
  9085.  
  9086.       while (Index_Type'POS (Lower_Bound1) + Size) <=
  9087.              Index_Type'POS (Sort_Array'LAST) loop
  9088.         I_Overflow := FALSE;
  9089.         J_Overflow := FALSE;
  9090.         Aux_Overflow := FALSE;
  9091.  
  9092.         -- Compute remaining indices.
  9093.  
  9094.         Lower_Bound2 := Index_Type'VAL (Index_Type'POS (Lower_Bound1) +
  9095.                                         Size);
  9096.         Upper_Bound1 := Index_Type'PRED (Lower_Bound2);
  9097.  
  9098.         if Index_Type'POS (Lower_Bound2) + Size - 1 >
  9099.            Index_Type'POS (Sort_Array'LAST) then
  9100.           Upper_Bound2 := Sort_Array'LAST;
  9101.         else
  9102.           Upper_Bound2 := Index_Type'VAL (Index_Type'POS (Lower_Bound2) +
  9103.                                           Size - 1);
  9104.         end if;
  9105.  
  9106.         -- Proceed through the two subfiles.
  9107.  
  9108.         I := Lower_Bound1;
  9109.         J := Lower_Bound2;
  9110.  
  9111.         while (I <= Upper_Bound1) and (J <= Upper_Bound2) loop
  9112.           -- Enter smaller into Auxiliary_Array.
  9113.  
  9114.           Update_Performance_Instrumentation (Local_Comparisons);
  9115.           Update_Performance_Instrumentation (Local_Exchanges);
  9116.  
  9117.           if (Sort_Array (I) < Sort_Array (J)) or
  9118.              Equal (Sort_Array (I),Sort_Array (J)) then
  9119.             Auxiliary_Array (Auxiliary_Index) := Sort_Array (I);
  9120.  
  9121.             if Auxiliary_Index /= Auxiliary_Array'LAST then
  9122.               Auxiliary_Index := Index_Type'SUCC (Auxiliary_Index);
  9123.             else
  9124.               Aux_Overflow := TRUE;
  9125.             end if;
  9126.  
  9127.             if I /= Sort_Array'LAST then
  9128.               I := Index_Type'SUCC (I);
  9129.             else
  9130.               I_Overflow := TRUE;
  9131.               exit;
  9132.             end if;
  9133.           else
  9134.             Auxiliary_Array (Auxiliary_Index) := Sort_Array (J);
  9135.  
  9136.             if Auxiliary_Index /= Auxiliary_Array'LAST then
  9137.               Auxiliary_Index := Index_Type'SUCC (Auxiliary_Index);
  9138.             else
  9139.               Aux_Overflow := TRUE;
  9140.             end if;
  9141.  
  9142.             if J /= Sort_Array'LAST then
  9143.               J := Index_Type'SUCC (J);
  9144.             else
  9145.               J_Overflow := TRUE;
  9146.               exit;
  9147.             end if;
  9148.           end if;
  9149.         end loop;  -- While loop.
  9150.  
  9151.         -- At this point one of the subfiles has been exhausted.
  9152.         -- Insert any remaining portions of the other file.
  9153.  
  9154.         while (not I_Overflow) and (I <= Upper_Bound1) loop
  9155.           Update_Performance_Instrumentation (Local_Exchanges);
  9156.  
  9157.           Auxiliary_Array (Auxiliary_Index) := Sort_Array (I);
  9158.  
  9159.           if I /= Sort_Array'LAST then
  9160.             I := Index_Type'SUCC (I);
  9161.           else
  9162.             I_Overflow := TRUE;
  9163.           end if;
  9164.  
  9165.           if Auxiliary_Index /= Auxiliary_Array'LAST then
  9166.             Auxiliary_Index := Index_Type'SUCC (Auxiliary_Index);
  9167.           else
  9168.             Aux_Overflow := TRUE;
  9169.           end if;
  9170.         end loop;
  9171.  
  9172.         while (not J_Overflow) and (J <= Upper_Bound2) loop
  9173.           Update_Performance_Instrumentation (Local_Exchanges);
  9174.  
  9175.           Auxiliary_Array (Auxiliary_Index) := Sort_Array (J);
  9176.  
  9177.           if J /= Sort_Array'LAST then
  9178.             J := Index_Type'SUCC (J);
  9179.           else
  9180.             J_Overflow := TRUE;
  9181.           end if;
  9182.  
  9183.           if Auxiliary_Index /= Auxiliary_Array'LAST then
  9184.             Auxiliary_Index := Index_Type'SUCC (Auxiliary_Index);
  9185.           else
  9186.             Aux_Overflow := TRUE;
  9187.           end if;
  9188.         end loop;
  9189.  
  9190.         -- Advance Lower_Bound1 to start of next pair of files.
  9191.  
  9192.         if Index_Type'POS (Upper_Bound2) + 1 <=
  9193.            Index_Type'POS (Sort_Array'LAST) then
  9194.           Lower_Bound1 := Index_Type'SUCC (Upper_Bound2);
  9195.         else
  9196.           Lower_Bound1 := Sort_Array'LAST;
  9197.         end if;
  9198.       end loop;  -- While loop.
  9199.  
  9200.       -- Copy any remaining single file.
  9201.  
  9202.       I := Lower_Bound1;
  9203.  
  9204.       while not Aux_Overflow loop
  9205.         Update_Performance_Instrumentation (Local_Exchanges);
  9206.  
  9207.         Auxiliary_Array (Auxiliary_Index) := Sort_Array (I);
  9208.  
  9209.         if Auxiliary_Index /= Auxiliary_Array'LAST then
  9210.           Auxiliary_Index := Index_Type'SUCC (Auxiliary_Index);
  9211.         else
  9212.           Aux_Overflow := TRUE;
  9213.         end if;
  9214.  
  9215.         if I /= Sort_Array'LAST then
  9216.           I := Index_Type'SUCC (I);
  9217.         else
  9218.           I_Overflow := TRUE;
  9219.         end if;
  9220.       end loop;
  9221.  
  9222.       -- Adjust Sort_Array and Size.
  9223.  
  9224.       Sort_Array := Auxiliary_Array;
  9225.  
  9226.       Size := Size * 2;
  9227.     end loop;  -- While loop.
  9228.  
  9229.     Number_of_Comparisons := Local_Comparisons;
  9230.     Number_of_Exchanges := Local_Exchanges;
  9231.   end Merge_Sort;
  9232.  
  9233.   procedure Sort (
  9234.     Sort_Array             : in out Array_Type;
  9235.     Number_of_Comparisons,
  9236.     Number_of_Exchanges    :    out Performance_Instrumentation_Type;
  9237.     Sort_Algorithm         : in     Sort_Algorithm_Type := Quicksort) is
  9238.   begin
  9239.     -- Call the right sorting algorithm.
  9240.  
  9241.     case Sort_Algorithm is
  9242.       when Quicksort =>
  9243.         Quicksort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9244.       when Recursive_Quicksort =>
  9245.         Recursive_Quicksort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9246.       when Bsort =>
  9247.         Bsort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9248.       when Bubble_Sort =>
  9249.         Bubble_Sort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9250.       when Bubble_Sort_with_Quick_Exit =>
  9251.         Bubble_Sort_with_Quick_Exit (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9252.       when Selection_Sort =>
  9253.         Selection_Sort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9254.       when Heapsort =>
  9255.         Heapsort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9256.       when Insertion_Sort =>
  9257.         Insertion_Sort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9258.       when Merge_Sort =>
  9259.         Merge_Sort (Sort_Array,Number_of_Comparisons,Number_of_Exchanges);
  9260.     end case;
  9261.   end Sort;
  9262.  
  9263.   -- Overloading of procedure Sort that does not return instrumentation
  9264.   -- analysis data follows below.
  9265.  
  9266.   procedure Sort (
  9267.     Sort_Array     : in out Array_Type;
  9268.     Sort_Algorithm : in     Sort_Algorithm_Type := Quicksort) is
  9269.  
  9270.     Dummy_Comparisons,
  9271.     Dummy_Exchanges    : Performance_Instrumentation_Type;
  9272.   begin
  9273.     Sort (Sort_Array,Dummy_Comparisons,Dummy_Exchanges,Sort_Algorithm);
  9274.   end Sort;
  9275.  
  9276.   -- Overloading of procedure Sort used to preserve original data and to
  9277.   -- return instrumentation analysis results follows below.
  9278.  
  9279.   procedure Sort (
  9280.     Unsorted_Array         : in     Array_Type;
  9281.     Sorted_Array           :    out Array_Type;
  9282.     Number_of_Comparisons,
  9283.     Number_of_Exchanges    :    out Performance_Instrumentation_Type;
  9284.     Sort_Algorithm         : in     Sort_Algorithm_Type := Quicksort) is
  9285.  
  9286.     Local_Array : Array_Type (Unsorted_Array'RANGE) := Unsorted_Array;
  9287.   begin
  9288.     Number_of_Comparisons := 0;
  9289.     Number_of_Exchanges   := 0;
  9290.  
  9291.     -- Check for equal length of both arrays.
  9292.  
  9293.     if Unsorted_Array'LENGTH /= Sorted_Array'LENGTH then
  9294.       raise Sort_Arrays_Length_Mismatch;
  9295.     end if;
  9296.  
  9297.     Sort (Local_Array,Number_of_Comparisons,Number_of_Exchanges,
  9298.       Sort_Algorithm);
  9299.  
  9300.     Sorted_Array := Local_Array;
  9301.   end Sort;
  9302.  
  9303.   -- Overloading of procedure Sort used to preserve the original data
  9304.   -- follows below.
  9305.  
  9306.   procedure Sort (
  9307.     Unsorted_Array : in     Array_Type;
  9308.     Sorted_Array   :    out Array_Type;
  9309.     Sort_Algorithm : in     Sort_Algorithm_Type := Quicksort) is
  9310.  
  9311.     Local_Array        : Array_Type (Unsorted_Array'RANGE) := Unsorted_Array;
  9312.     Dummy_Comparisons,
  9313.     Dummy_Exchanges    : Performance_Instrumentation_Type;
  9314.   begin
  9315.     -- Check for equal length of both arrays.
  9316.  
  9317.     if Unsorted_Array'LENGTH /= Sorted_Array'LENGTH then
  9318.       raise Sort_Arrays_Length_Mismatch;
  9319.     end if;
  9320.  
  9321.     Sort (Local_Array,Dummy_Comparisons,Dummy_Exchanges,Sort_Algorithm);
  9322.  
  9323.     Sorted_Array := Local_Array;
  9324.   end Sort;
  9325.  
  9326.   -- Overloading of function Sort used in inline expressions follows below.
  9327.  
  9328.   function Sort (
  9329.     Sort_Array     : in Array_Type;
  9330.     Sort_Algorithm : in Sort_Algorithm_Type := Quicksort)
  9331.     return Array_Type is
  9332.  
  9333.     Sorted_Array       : Array_Type (Sort_Array'RANGE) := Sort_Array;
  9334.     Dummy_Comparisons,
  9335.     Dummy_Exchanges    : Performance_Instrumentation_Type;
  9336.   begin
  9337.     Sort (Sorted_Array,Dummy_Comparisons,Dummy_Exchanges,Sort_Algorithm);
  9338.     
  9339.     return Sorted_Array;
  9340.   end Sort;
  9341. end Sort_Utilities;
  9342. --::::::::::
  9343. --stringer.bdy
  9344. --::::::::::
  9345. package body STRING_MANIPULATOR is
  9346.    
  9347.    procedure LOAD (FROM           : in STRING;
  9348.                    TO             : out STRING;
  9349.                    FILL_CHARACTER : in CHARACTER := ' ') is
  9350.       
  9351.       --========================= PDL ===========================
  9352.       --|ABSTRACT:
  9353.       --|    LOAD loads the TO string with the content of the
  9354.       --|    FROM string.  If the TO string is longer than the
  9355.       --|    FROM string, the TO string is right-filled with the
  9356.       --|    FILL_CHARACTER.  If the TO string is shorter than
  9357.       --|    the FROM string, the slice of the FROM string that
  9358.       --|    will fit in the TO string will be copied into the TO
  9359.       --|    string.
  9360.       --|DESIGN DESCRIPTION:
  9361.       --|    If the length of the TO string is greater than or
  9362.       --|      equal to the length of the FROM string
  9363.       --|        Copy the FROM string into the first slice of the
  9364.       --|          TO string
  9365.       --|        Copy the FILL_CHARACTER into the rest of the TO
  9366.       --|          string
  9367.       --|    Else
  9368.       --|        Copy the first slice of the FROM string into the
  9369.       --|          TO string
  9370.       --|    End if
  9371.       --=========================================================
  9372.       
  9373.    begin
  9374.       if TO'LENGTH >= FROM'LENGTH then
  9375.          TO (TO'FIRST .. TO'FIRST + FROM'LENGTH - 1) := FROM;
  9376.          TO (TO'FIRST + FROM'LENGTH .. TO'LAST) := (others => FILL_CHARACTER);
  9377.       else
  9378.          TO := FROM (FROM'FIRST .. FROM'FIRST + TO'LENGTH - 1);
  9379.       end if;
  9380.    end LOAD;
  9381.    
  9382.    procedure LOAD (FROM           : in STRING;
  9383.                    TO             : out STRING;
  9384.                    LAST           : out NATURAL;
  9385.                    FILL_CHARACTER : in CHARACTER := ' ') is
  9386.       
  9387.       --========================= PDL ===========================
  9388.       --|ABSTRACT:
  9389.       --|    LOAD loads the TO string with the content of the
  9390.       --|    FROM string.  If the TO string is longer than the
  9391.       --|    FROM string, the TO string is right-filled with the
  9392.       --|    FILL_CHARACTER.  If the TO string is shorter than
  9393.       --|    the FROM string, the slice of the FROM string that
  9394.       --|    will fit in the TO string will be copied into the TO
  9395.       --|    string.  LOAD also returns the number of characters
  9396.       --|    in FROM string as the variable LAST.
  9397.       --|DESIGN DESCRIPTION:
  9398.       --|    If the length of the TO string is greater than or
  9399.       --|      equal to the length of the FROM string
  9400.       --|        Copy the FROM string into the first slice of the
  9401.       --|          TO string
  9402.       --|        Copy the FILL_CHARACTER into the rest of the TO
  9403.       --|          string
  9404.       --|        Set LAST to FROM'LENGTH + TO'FIRST - 1
  9405.       --|    Else
  9406.       --|        Copy the first slice of the FROM string into the
  9407.       --|          TO string
  9408.       --|        Set LAST to TO'LAST
  9409.       --|    End if
  9410.       --=========================================================
  9411.       
  9412.    begin
  9413.       if TO'LENGTH >= FROM'LENGTH then
  9414.          TO (TO'FIRST .. TO'FIRST + FROM'LENGTH - 1) := FROM;
  9415.          TO (TO'FIRST + FROM'LENGTH .. TO'LAST) := (others => FILL_CHARACTER);
  9416.          LAST := FROM'LENGTH + TO'FIRST - 1;
  9417.       else
  9418.          TO   := FROM (FROM'FIRST .. FROM'FIRST + TO'LENGTH - 1);
  9419.          LAST := TO'LAST;
  9420.       end if;
  9421.    end LOAD;
  9422.    
  9423.    procedure GUARDED_LOAD (FROM           : in STRING;
  9424.                            TO             : out STRING;
  9425.                            FILL_CHARACTER : in CHARACTER := ' ') is
  9426.       
  9427.       --========================= PDL ===========================
  9428.       --|ABSTRACT:
  9429.       --|    GUARDED_LOAD loads the TO string with the content of
  9430.       --|    the FROM string.  If the TO string is longer than the
  9431.       --|    FROM string, the TO string is right-filled with the
  9432.       --|    FILL_CHARACTER.  If the TO string is shorter than
  9433.       --|    the FROM string, STRING_OVERFLOW is raised.
  9434.       --|DESIGN DESCRIPTION:
  9435.       --|    If the length of the TO string is greater than or
  9436.       --|      equal to the length of the FROM string
  9437.       --|        Copy the FROM string into the first slice of the
  9438.       --|          TO string
  9439.       --|        Copy the FILL_CHARACTER into the rest of the TO
  9440.       --|          string
  9441.       --|    Else
  9442.       --|        Raise STRING_OVERFLOW
  9443.       --|    End if
  9444.       --=========================================================
  9445.       
  9446.    begin
  9447.       if TO'LENGTH >= FROM'LENGTH then
  9448.          TO (TO'FIRST .. TO'FIRST + FROM'LENGTH - 1) := FROM;
  9449.          TO (TO'FIRST + FROM'LENGTH .. TO'LAST) := (others => FILL_CHARACTER);
  9450.       else
  9451.          raise STRING_OVERFLOW;
  9452.       end if;
  9453.    end GUARDED_LOAD;
  9454.    
  9455.    procedure GUARDED_LOAD (FROM           : in STRING;
  9456.                            TO             : out STRING;
  9457.                            LAST           : out NATURAL;
  9458.                            FILL_CHARACTER : in CHARACTER := ' ') is
  9459.       
  9460.       --========================= PDL ===========================
  9461.       --|ABSTRACT:
  9462.       --|    GUARDED_LOAD loads the TO string with the content of
  9463.       --|    the FROM string.  If the TO string is longer than the
  9464.       --|    FROM string, the TO string is right-filled with the
  9465.       --|    FILL_CHARACTER.  If the TO string is shorter than
  9466.       --|    the FROM string, STRING_OVERFLOW is raised.  LAST is
  9467.       --|    the index of the FROM character in the TO string.
  9468.       --|DESIGN DESCRIPTION:
  9469.       --|    If the length of the TO string is greater than or
  9470.       --|      equal to the length of the FROM string
  9471.       --|        Copy the FROM string into the first slice of the
  9472.       --|          TO string
  9473.       --|        Copy the FILL_CHARACTER into the rest of the TO
  9474.       --|          string
  9475.       --|        Set LAST to FROM'LENGTH + TO'FIRST - 1
  9476.       --|    Else
  9477.       --|        Raise STRING_OVERFLOW
  9478.       --|    End if
  9479.       --=========================================================
  9480.       
  9481.    begin
  9482.       if TO'LENGTH >= FROM'LENGTH then
  9483.          TO (TO'FIRST .. TO'FIRST + FROM'LENGTH - 1) := FROM;
  9484.          TO (TO'FIRST + FROM'LENGTH .. TO'LAST) := (others => FILL_CHARACTER);
  9485.          LAST := FROM'LENGTH + TO'FIRST - 1;
  9486.       else
  9487.          raise STRING_OVERFLOW;
  9488.       end if;
  9489.    end GUARDED_LOAD;
  9490.    
  9491.    procedure FILL (WHAT      : out STRING;
  9492.                    WITH_ITEM : in CHARACTER := ' ') is
  9493.       
  9494.       --========================= PDL ===========================
  9495.       --|ABSTRACT:
  9496.       --|    FILL fills the string WHAT with the character 
  9497.       --|    WITH_ITEM.
  9498.       --|DESIGN DESCRIPTION:
  9499.       --|    Loop over WHAT'RANGE
  9500.       --|        Store WITH_ITEM into WHAT(I)
  9501.       --|    End Loop
  9502.       --=========================================================
  9503.       
  9504.    begin
  9505.       for I in WHAT'RANGE loop
  9506.          WHAT (I) := WITH_ITEM;
  9507.       end loop;
  9508.    end FILL;
  9509.    
  9510.    function IS_FILLED (WHAT      : in STRING;
  9511.                        WITH_ITEM : in CHARACTER := ' ') return BOOLEAN is
  9512.       
  9513.       --========================= PDL ===========================
  9514.       --|ABSTRACT:
  9515.       --|    IS_FILLED returns TRUE if all characters of the
  9516.       --|    string WHAT are equal to WITH_ITEM.  FALSE is 
  9517.       --|    returned otherwise.
  9518.       --|DESIGN DESCRIPTION:
  9519.       --|    Initialize RESULT to TRUE
  9520.       --|    Loop over WHAT'RANGE
  9521.       --|        If WHAT(I) is not equal to WITH_ITEM, exit with
  9522.       --|          RESULT set to FALSE
  9523.       --|    End Loop
  9524.       --|    Return RESULT
  9525.       --=========================================================
  9526.       
  9527.       RESULT : BOOLEAN := TRUE;
  9528.    begin
  9529.       for I in WHAT'RANGE loop
  9530.          if WHAT (I) /= WITH_ITEM then
  9531.             RESULT := FALSE;
  9532.             exit ;
  9533.          end if;
  9534.       end loop;
  9535.       return RESULT;
  9536.    end IS_FILLED;
  9537.    
  9538. end STRING_MANIPULATOR;
  9539. --::::::::::
  9540. --testlog.bdy
  9541. --::::::::::
  9542. -- **************************************************
  9543. -- *                                                *
  9544. -- *  Test_Log                                      *  BODY
  9545. -- *                                                *
  9546. -- **************************************************
  9547. with Text_IO;
  9548. package body Test_Log is
  9549. --| Notes (none)
  9550.  
  9551.   File_Report   : BOOLEAN := FALSE;
  9552.   FID           : Text_IO.FILE_TYPE;
  9553.   Test_Counter  : NATURAL := 0;
  9554.   Error_Counter : NATURAL := 0;
  9555.   Indent_String : constant STRING := "    ";
  9556.   Current_Mode  : MODE := SILENT;
  9557.   Fill_String   : constant STRING :=
  9558.     "                                                            "; -- 60
  9559.  
  9560.   Test_ID_Field_Length    : NATURAL;
  9561.   String_Field_Length     : NATURAL;
  9562.   Integer_Field_Length    : NATURAL;
  9563.   Float_Fore_Field_Length : NATURAL;
  9564.   Float_Aft_Field_Length  : NATURAL;
  9565.   Float_Exp_Field_Length  : NATURAL;
  9566.  
  9567.   package Int_IO is new Text_IO.Integer_IO(INTEGER);
  9568.   package Flt_IO is new Text_IO.Float_IO(FLOAT);
  9569.  
  9570.   -- ..................................................
  9571.   -- .                                                .
  9572.   -- .  Test_Log.To_ID                                .  SPEC & BODY
  9573.   -- .                                                .
  9574.   -- ..................................................
  9575.   function To_ID(S : in STRING) return STRING is
  9576.   begin
  9577.     if S'LENGTH < Test_ID_Field_Length then
  9578.       return S & Fill_String(1..Test_ID_Field_Length-S'LENGTH);
  9579.     else
  9580.       return S;
  9581.     end if;
  9582.   end To_ID;
  9583.  
  9584.   -- ..................................................
  9585.   -- .                                                .
  9586.   -- .  Test_Log.To_String                            .  SPEC & BODY
  9587.   -- .                                                .
  9588.   -- ..................................................
  9589.   function To_String(S : in STRING) return STRING is
  9590.   begin
  9591.     if S'LENGTH < String_Field_Length then
  9592.       return """" & S & """" &
  9593.         Fill_String(1..String_Field_Length-S'LENGTH);
  9594.     else
  9595.       return """" & S & """";
  9596.     end if;
  9597.   end To_String;
  9598.  
  9599.   -- ..................................................
  9600.   -- .                                                .
  9601.   -- .  Test_Log.Show_Result                          .  SPEC & BODY
  9602.   -- .                                                .
  9603.   -- ..................................................
  9604.   function Show_Result(R : in TEST_RESULT) return STRING is
  9605.   begin
  9606.     return TEST_RESULT'IMAGE(R);
  9607.   end Show_Result;
  9608.  
  9609.   -- ..................................................
  9610.   -- .                                                .
  9611.   -- .  Test_Log.Set_Mode                             .  BODY
  9612.   -- .                                                .
  9613.   -- ..................................................
  9614.   procedure Set_Mode (To : in MODE) is
  9615.     Looping : BOOLEAN := TRUE;
  9616.     Inline  : STRING(1..10);
  9617.     Inlast  : NATURAL;
  9618.   begin
  9619.     case To is
  9620.       when USER_SELECTABLE =>
  9621.         while Looping loop
  9622.           Text_IO.Put("Enter Test Mode (F=File, V=Verbose, S=Silent): ");
  9623.           Text_IO.Get_Line(Inline, Inlast);
  9624.           if Inlast > 0 then
  9625.             case Inline(1) is
  9626.               when 'f' | 'F' =>
  9627.                 Current_Mode := VERBOSE;
  9628.                 if not File_Report then
  9629.                   File_Report := TRUE;
  9630.                   begin
  9631.                     Text_IO.Create(FID, Text_IO.OUT_FILE, Test_Log_File);
  9632.                     Text_IO.Put_Line
  9633.                       ("Output file " & Test_Log_File & " created");
  9634.                   exception
  9635.                     when others =>
  9636.                       Text_IO.Put_Line
  9637.                         ("Cannot create output file " & Test_Log_File);
  9638.                       raise REPORT_FILE_ERROR;
  9639.                   end;
  9640.                   Text_IO.Set_Output(FID);
  9641.                 end if;
  9642.                 Looping := FALSE;
  9643.               when 's' | 'S' =>
  9644.                 Current_Mode := SILENT;
  9645.                 Looping := FALSE;
  9646.               when 'v' | 'V' =>
  9647.                 Current_Mode := VERBOSE;
  9648.                 Looping := FALSE;
  9649.               when others =>
  9650.                 Text_IO.Put_Line("  Invalid input -- retry");
  9651.             end case;
  9652.           end if;
  9653.         end loop;
  9654.       when REPORT_TO_FILE =>
  9655.         Current_Mode := VERBOSE;
  9656.         if not File_Report then
  9657.           File_Report := TRUE;
  9658.           begin
  9659.             Text_IO.Create(FID, Text_IO.OUT_FILE, Test_Log_File);
  9660.             Text_IO.Put_Line
  9661.               ("Output file " & Test_Log_File & " created");
  9662.           exception
  9663.             when others =>
  9664.               Text_IO.Put_Line
  9665.                 ("Cannot create output file " & Test_Log_File);
  9666.               raise REPORT_FILE_ERROR;
  9667.           end;
  9668.           Text_IO.Set_Output(FID);
  9669.         end if;
  9670.       when VERBOSE | SILENT =>
  9671.         Current_Mode := To;
  9672.     end case;
  9673.   end Set_Mode;
  9674.  
  9675.   -- ..................................................
  9676.   -- .                                                .
  9677.   -- .  Test_Log.Set_Test_ID_Field_Width              .  BODY
  9678.   -- .                                                .
  9679.   -- ..................................................
  9680.   procedure Set_Test_ID_Field_Width (To : in NATURAL := 10) is
  9681.   begin
  9682.     Test_ID_Field_Length := To;
  9683.   end Set_Test_ID_Field_Width;
  9684.  
  9685.   -- ..................................................
  9686.   -- .                                                .
  9687.   -- .  Test_Log.Set_String_Field_Width               .  BODY
  9688.   -- .                                                .
  9689.   -- ..................................................
  9690.   procedure Set_String_Field_Width (To : in NATURAL := 20) is
  9691.   begin
  9692.     String_Field_Length := To;
  9693.   end Set_String_Field_Width;
  9694.  
  9695.   -- ..................................................
  9696.   -- .                                                .
  9697.   -- .  Test_Log.Set_Integer_Field_Width              .  BODY
  9698.   -- .                                                .
  9699.   -- ..................................................
  9700.   procedure Set_Integer_Field_Width (To : in NATURAL := 20) is
  9701.   begin
  9702.     Integer_Field_Length := To;
  9703.   end Set_Integer_Field_Width;
  9704.  
  9705.   -- ..................................................
  9706.   -- .                                                .
  9707.   -- .  Test_Log.Set_Float_Field_Width                .  BODY
  9708.   -- .                                                .
  9709.   -- ..................................................
  9710.   procedure Set_Float_Field_Width
  9711.     (Before_Decimal : in NATURAL := 2;
  9712.      After_Decimal  : in NATURAL := 5;
  9713.      In_Exponent    : in NATURAL := 4) is
  9714.   begin
  9715.     Float_Fore_Field_Length := Before_Decimal;
  9716.     Float_Aft_Field_Length  := After_Decimal;
  9717.     Float_Exp_Field_Length  := In_Exponent;
  9718.   end Set_Float_Field_Width;
  9719.  
  9720.   -- ..................................................
  9721.   -- .                                                .
  9722.   -- .  Test_Log.Reset                                .  BODY
  9723.   -- .                                                .
  9724.   -- ..................................................
  9725.   procedure Reset is
  9726.   begin
  9727.     Test_Counter  := 0;
  9728.     Error_Counter := 0;
  9729.   end Reset;
  9730.  
  9731.   -- ..................................................
  9732.   -- .                                                .
  9733.   -- .  Test_Log.Compare                              .  BODY
  9734.   -- .                                                .
  9735.   -- ..................................................
  9736.   procedure Compare(Test_ID : in STRING;
  9737.                     Expected_Result : in STRING;
  9738.                     Actual_Result   : in STRING) is
  9739.     Result : TEST_RESULT := PASS;
  9740.   begin
  9741.     Test_Counter := Test_Counter + 1;
  9742.     if Expected_Result /= Actual_Result then
  9743.       Result := FAIL;
  9744.       Error_Counter := Error_Counter + 1;
  9745.       if Current_Mode = SILENT then
  9746.         Text_IO.Put_Line(Test_ID);
  9747.       end if;
  9748.     end if;
  9749.     if Current_Mode = VERBOSE then
  9750.       Text_IO.Put_Line(To_ID(Test_ID) & "  " &
  9751.         To_String(Expected_Result) & "  " &
  9752.         To_String(Actual_Result) & "  " &
  9753.         Show_Result(Result));
  9754.     end if;
  9755.   end Compare;
  9756.  
  9757.   -- ..................................................
  9758.   -- .                                                .
  9759.   -- .  Test_Log.Compare                              .  BODY
  9760.   -- .                                                .
  9761.   -- ..................................................
  9762.   procedure Compare(Test_ID         : in STRING;
  9763.                     Expected_Result : in INTEGER;
  9764.                     Actual_Result   : in INTEGER) is
  9765.     Result : TEST_RESULT := PASS;
  9766.   begin
  9767.     Test_Counter := Test_Counter + 1;
  9768.     if Expected_Result /= Actual_Result then
  9769.       Result := FAIL;
  9770.       Error_Counter := Error_Counter + 1;
  9771.       if Current_Mode = SILENT then
  9772.         Text_IO.Put_Line(Test_ID);
  9773.       end if;
  9774.     end if;
  9775.     if Current_Mode = VERBOSE then
  9776.       Text_IO.Put(To_ID(Test_ID) & "  ");
  9777.       Int_IO.Put(Expected_Result, Integer_Field_Length);
  9778.       Text_IO.Put("  ");
  9779.       Int_IO.Put(Actual_Result, Integer_Field_Length);
  9780.       Text_IO.Put_Line("  " & Show_Result(Result));
  9781.     end if;
  9782.   end Compare;
  9783.  
  9784.   -- ..................................................
  9785.   -- .                                                .
  9786.   -- .  Test_Log.Compare                              .  BODY
  9787.   -- .                                                .
  9788.   -- ..................................................
  9789.   procedure Compare(Test_ID         : in STRING;
  9790.                     Expected_Result : in FLOAT;
  9791.                     Actual_Result   : in FLOAT;
  9792.                     Tolerance       : in FLOAT) is
  9793.     Result : TEST_RESULT := PASS;
  9794.   begin
  9795.     Test_Counter := Test_Counter + 1;
  9796.     if abs(Expected_Result - Actual_Result) > Tolerance then
  9797.       Result := FAIL;
  9798.       Error_Counter := Error_Counter + 1;
  9799.       if Current_Mode = SILENT then
  9800.         Text_IO.Put_Line(Test_ID);
  9801.       end if;
  9802.     end if;
  9803.     if Current_Mode = VERBOSE then
  9804.       Text_IO.Put(To_ID(Test_ID) & "  ");
  9805.       Flt_IO.Put(Expected_REsult, Float_Fore_Field_Length,
  9806.                                   Float_Aft_Field_Length,
  9807.                                   Float_Exp_Field_Length);
  9808.       Text_IO.Put("  ");
  9809.       Flt_IO.Put(Actual_Result, Float_Fore_Field_Length,
  9810.                                 Float_Aft_Field_Length,
  9811.                                 Float_Exp_Field_Length);
  9812.       Text_IO.Put_Line("  " & Show_Result(Result));
  9813.     end if;
  9814.   end Compare;
  9815.  
  9816.   -- ..................................................
  9817.   -- .                                                .
  9818.   -- .  Test_Log.Enter_Test_Result                    .  BODY
  9819.   -- .                                                .
  9820.   -- ..................................................
  9821.   procedure Enter_Test_Result(Test_ID : in STRING;
  9822.                               Result  : in TEST_RESULT) is
  9823.   begin
  9824.     Test_Counter := Test_Counter + 1;
  9825.     if Result = FAIL then
  9826.       Error_Counter := Error_Counter + 1;
  9827.       if Current_Mode = SILENT then
  9828.         Text_IO.Put_Line(Test_ID);
  9829.       end if;
  9830.     end if;
  9831.     if Current_Mode = VERBOSE then
  9832.       Text_IO.Put_Line(To_ID(Test_ID) & "  " &
  9833.                        Show_Result(Result));
  9834.     end if;
  9835.   end Enter_Test_Result;
  9836.  
  9837.   -- ..................................................
  9838.   -- .                                                .
  9839.   -- .  Test_Log.Error_Count                          .  BODY
  9840.   -- .                                                .
  9841.   -- ..................................................
  9842.   function Error_Count return NATURAL is
  9843.   begin
  9844.     return Error_Counter;
  9845.   end Error_Count;
  9846.  
  9847.   -- ..................................................
  9848.   -- .                                                .
  9849.   -- .  Test_Log.Test_Count                           .  BODY
  9850.   -- .                                                .
  9851.   -- ..................................................
  9852.   function Test_Count return NATURAL is
  9853.   begin
  9854.     return Test_Counter;
  9855.   end Test_Count;
  9856.  
  9857.   -- ..................................................
  9858.   -- .                                                .
  9859.   -- .  Test_Log.Write                                .  BODY
  9860.   -- .                                                .
  9861.   -- ..................................................
  9862.   procedure Write(Message : in STRING := "") is
  9863.   begin
  9864.     Text_IO.Put_Line(Message);
  9865.   end Write;
  9866.  
  9867.   -- ..................................................
  9868.   -- .                                                .
  9869.   -- .  Test_Log.Report                               .  BODY
  9870.   -- .                                                .
  9871.   -- ..................................................
  9872.   procedure Report(Message : in STRING := "") is
  9873.     Indent : BOOLEAN := FALSE;
  9874.   begin
  9875.     if Message'Length > 0 then
  9876.       Text_IO.Put_Line(Message);
  9877.       Indent := TRUE;
  9878.     end if;
  9879.     if Indent then
  9880.       Text_IO.Put(Indent_String);
  9881.     end if;
  9882.     Text_IO.Put_Line("Test  Counter = " &
  9883.                      NATURAL'IMAGE(Test_Counter));
  9884.     if Indent then
  9885.       Text_IO.Put(Indent_String);
  9886.     end if;
  9887.     Text_IO.Put_Line("Error Counter = " &
  9888.                      NATURAL'IMAGE(Error_Counter));
  9889.   end Report;
  9890.  
  9891.   -- ..................................................
  9892.   -- .                                                .
  9893.   -- .  Test_Log.Close                                .  BODY
  9894.   -- .                                                .
  9895.   -- ..................................................
  9896.   procedure Close is
  9897.   begin
  9898.     if File_Report then
  9899.       Text_IO.Close(FID);
  9900.       File_Report := FALSE;
  9901.       Text_IO.Set_Output(Text_IO.Standard_Output);
  9902.     end if;
  9903.   end Close;
  9904.  
  9905. begin -- Initialize Test_Log
  9906.   Set_Test_ID_Field_Width;
  9907.   Set_String_Field_Width;
  9908.   Set_Integer_Field_Width;
  9909.   Set_Float_Field_Width;
  9910. end Test_Log;
  9911. --::::::::::
  9912. --binfile.bdy
  9913. --::::::::::
  9914. -- **************************************************
  9915. -- *                                                *
  9916. -- *  Binary_File                                   *  BODY
  9917. -- *                                                *
  9918. -- **************************************************
  9919. with CS_Parts_Types;  -- for BYTE type
  9920. use  CS_Parts_Types;
  9921. with Sequential_IO;
  9922. with Unchecked_Deallocation;
  9923. package body Binary_File is
  9924. --| Notes (none)
  9925.  
  9926.   package BIO is new Sequential_IO(BYTE);
  9927.   type FILE_OBJECT is record
  9928.     F : BIO.FILE_TYPE;
  9929.   end record;
  9930.  
  9931.   procedure Free is new Unchecked_Deallocation (FILE_OBJECT, FILE_TYPE);
  9932.  
  9933.   -- ...................................................
  9934.   -- .                                                 .
  9935.   -- .  Binary_File.Create                             .  BODY
  9936.   -- .                                                 .
  9937.   -- ...................................................
  9938.   procedure Create (File : in out FILE_TYPE;
  9939.                     Name : in STRING) is
  9940.   --| Exceptions
  9941.   --|   Device_Error   -- raised if file cannot be created
  9942.   --|                  -- due to a hardware error
  9943.   --|   Name_Error     -- raised if Name is not a valid file
  9944.   --|                  -- or directory reference
  9945.   --|   Status_Error   -- raised if file Name is already
  9946.   --|                  -- open
  9947.   --|   Use_Error      -- raised if file Name exists and is
  9948.   --|                  -- read/only
  9949.   --|
  9950.   --| Notes (none)
  9951.   begin  -- Create
  9952.     File := new FILE_OBJECT;
  9953.     BIO.Create (File.F, BIO.OUT_FILE, Name);
  9954.   exception
  9955.     when BIO.Device_Error =>
  9956.       raise Device_Error;
  9957.     when BIO.Name_Error =>
  9958.       raise Name_Error;
  9959.     when BIO.Status_Error =>
  9960.       raise Status_Error;
  9961.     when BIO.Use_Error =>
  9962.       raise Use_Error;
  9963.     when others =>
  9964.       raise Unexpected_Error;
  9965.   end Create;
  9966.  
  9967.   -- ...................................................
  9968.   -- .                                                 .
  9969.   -- .  Binary_File.Open                               .  BODY
  9970.   -- .                                                 .
  9971.   -- ...................................................
  9972.   procedure Open   (File : in out FILE_TYPE;
  9973.                     Name : in STRING) is
  9974.   --| Exceptions
  9975.   --|   Device_Error   -- raised if file cannot be opened
  9976.   --|                  -- due to a hardware error
  9977.   --|   Name_Error     -- raised if Name is not a valid file
  9978.   --|                  -- or directory reference
  9979.   --|   Status_Error   -- raised if file Name is already
  9980.   --|                  -- open
  9981.   --|   Use_Error      -- raised if file Name is write/only
  9982.   --|
  9983.   --| Notes (none)
  9984.   begin -- Open
  9985.     File := new FILE_OBJECT;
  9986.     BIO.Open (File.F, BIO.IN_FILE, Name);
  9987.   exception
  9988.     when BIO.Device_Error =>
  9989.       raise Device_Error;
  9990.     when BIO.Name_Error =>
  9991.       raise Name_Error;
  9992.     when BIO.Status_Error =>
  9993.       raise Status_Error;
  9994.     when BIO.Use_Error =>
  9995.       raise Use_Error;
  9996.     when others =>
  9997.       raise Unexpected_Error;
  9998.   end Open;
  9999.  
  10000.   -- ...................................................
  10001.   -- .                                                 .
  10002.   -- .  Binary_File.Close                              .  BODY
  10003.   -- .                                                 .
  10004.   -- ...................................................
  10005.   procedure Close (File : in out FILE_TYPE) is
  10006.   --| Notes (none)
  10007.   begin -- Close
  10008.     BIO.Close (File.F);
  10009.     Free (File);
  10010.   exception
  10011.     when others => raise Unexpected_Error;
  10012.   end Close;
  10013.  
  10014.   -- ...................................................
  10015.   -- .                                                 .
  10016.   -- .  Binary_File.Reset                              .  SPEC
  10017.   -- .                                                 .
  10018.   -- ...................................................
  10019.   procedure Reset (File : in out FILE_TYPE;
  10020.                    Mode : in FILE_MODE := IN_FILE) is
  10021.   --| Exceptions
  10022.   --|   Device_Error   -- raised if file cannot be accessed
  10023.   --|                  -- due to a hardware error
  10024.   --|   Name_Error     -- raised if Name is not a valid file
  10025.   --|                  -- or directory reference
  10026.   --|   Status_Error   -- raised if file Name is already
  10027.   --|                  -- open
  10028.   --|   Use_Error      -- raised if file Name exists and is
  10029.   --|                  -- read/only
  10030.   --|
  10031.   --| Notes (none)
  10032.   begin -- Reset
  10033.     case Mode is
  10034.       when IN_FILE =>
  10035.         BIO.Reset (File.F, BIO.IN_FILE);
  10036.       when OUT_FILE =>
  10037.         BIO.Reset (File.F, BIO.OUT_FILE);
  10038.     end case;
  10039.   exception
  10040.     when BIO.Device_Error =>
  10041.       raise Device_Error;
  10042.     when BIO.Name_Error =>
  10043.       raise Name_Error;
  10044.     when BIO.Status_Error =>
  10045.       raise Status_Error;
  10046.     when BIO.Use_Error =>
  10047.       raise Use_Error;
  10048.     when others =>
  10049.       raise Unexpected_Error;
  10050.   end Reset;
  10051.  
  10052.   -- ...................................................
  10053.   -- .                                                 .
  10054.   -- .  Binary_File.Mode                               .  BODY
  10055.   -- .                                                 .
  10056.   -- ...................................................
  10057.   function Mode (File : in FILE_TYPE) return FILE_MODE is
  10058.   --| Notes (none)
  10059.     Result1 : BIO.FILE_MODE;
  10060.     Result  : FILE_MODE;
  10061.   begin -- Mode
  10062.     Result1 := BIO.Mode (File.F);
  10063.     case Result1 is
  10064.       when BIO.IN_FILE  => Result := IN_FILE;
  10065.       when BIO.OUT_FILE => Result := OUT_FILE;
  10066.     end case;
  10067.     return Result;
  10068.   exception
  10069.     when others => raise Unexpected_Error;
  10070.   end Mode;
  10071.  
  10072.   -- ...................................................
  10073.   -- .                                                 .
  10074.   -- .  Binary_File.Name                               .  BODY
  10075.   -- .                                                 .
  10076.   -- ...................................................
  10077.   function Name (File : in FILE_TYPE) return STRING is
  10078.   --| Notes (none)
  10079.   begin -- Name
  10080.     return BIO.Name (File.F);
  10081.   exception
  10082.     when others => raise Unexpected_Error;
  10083.   end Name;
  10084.  
  10085.   -- ...................................................
  10086.   -- .                                                 .
  10087.   -- .  Binary_File.Is_Open                            .  BODY
  10088.   -- .                                                 .
  10089.   -- ...................................................
  10090.   function Is_Open (File : in FILE_TYPE) return BOOLEAN is
  10091.   --| Notes (none)
  10092.   begin -- Is_Open
  10093.     return BIO.Is_Open (File.F);
  10094.   exception
  10095.     when others => raise Unexpected_Error;
  10096.   end Is_Open;
  10097.  
  10098.   -- ...................................................
  10099.   -- .                                                 .
  10100.   -- .  Binary_File.Is_End                             .  BODY
  10101.   -- .                                                 .
  10102.   -- ...................................................
  10103.   function Is_End  (File : in FILE_TYPE) return BOOLEAN is
  10104.   --| Notes (none)
  10105.   begin -- Is_End
  10106.     return BIO.End_of_File (File.F);
  10107.   exception
  10108.     when others => raise Unexpected_Error;
  10109.   end Is_End;
  10110.  
  10111.   -- ...................................................
  10112.   -- .                                                 .
  10113.   -- .  Binary_File.Read                               .  BODY
  10114.   -- .                                                 .
  10115.   -- ...................................................
  10116.   procedure Read  (File : in FILE_TYPE;
  10117.                    Item : out BYTE) is
  10118.   --| Exceptions
  10119.   --|   Device_Error   -- raised if File cannot be accessed
  10120.   --|                  -- due to a hardware error
  10121.   --|   End_Error      -- raised if the next byte to be
  10122.   --|                  -- returned is beyond the end of
  10123.   --|                  -- the File
  10124.   --|   Mode_Error     -- raised if File is opened for
  10125.   --|                  -- output (mode OUT_FILE)
  10126.   --|   Status_Error   -- raised if File has not been
  10127.   --|                  -- OPENed
  10128.   --|
  10129.   --| Notes (none)
  10130.   begin -- Read
  10131.     BIO.Read (File.F, Item);
  10132.   exception
  10133.     when BIO.Device_Error =>
  10134.       raise Device_Error;
  10135.     when BIO.End_Error =>
  10136.       raise End_Error;
  10137.     when BIO.Mode_Error =>
  10138.       raise Mode_Error;
  10139.     when BIO.Status_Error =>
  10140.       raise Status_Error;
  10141.     when others =>
  10142.       raise Unexpected_Error;
  10143.   end Read;
  10144.  
  10145.   -- ...................................................
  10146.   -- .                                                 .
  10147.   -- .  Binary_File.Read                               .  BODY
  10148.   -- .                                                 .
  10149.   -- ...................................................
  10150.   procedure Read  (File : in FILE_TYPE;
  10151.                    Item : out BLOCK) is
  10152.   --| Exceptions
  10153.   --|   Data_Error     -- raised if a full BLOCK could
  10154.   --|                  -- not be read from the file
  10155.   --|   Device_Error   -- raised if File cannot be accessed
  10156.   --|                  -- due to a hardware error
  10157.   --|   End_Error      -- raised if the next byte to be
  10158.   --|                  -- returned is beyond the end of
  10159.   --|                  -- the File
  10160.   --|   Mode_Error     -- raised if File is opened for
  10161.   --|                  -- output (mode OUT_FILE)
  10162.   --|   Status_Error   -- raised if File has not been
  10163.   --|                  -- OPENed
  10164.   --|
  10165.   --| Notes (none)
  10166.     Next_Byte : BYTE;
  10167.   begin -- Read
  10168.     for I in Item'First .. Item'Last loop
  10169.       begin
  10170.         BIO.Read (File.F, Next_Byte);
  10171.       exception
  10172.         when BIO.End_Error =>
  10173.           if I = Item'First then
  10174.             raise End_Error;
  10175.           else
  10176.             raise Data_Error;
  10177.           end if;
  10178.         when others =>
  10179.           raise;
  10180.       end;
  10181.       Item(I) := Next_Byte;
  10182.     end loop;
  10183.   exception
  10184.     when BIO.Device_Error =>
  10185.       raise Device_Error;
  10186.     when BIO.Mode_Error =>
  10187.       raise Mode_Error;
  10188.     when BIO.Status_Error =>
  10189.       raise Status_Error;
  10190.     when End_Error | Data_Error =>
  10191.       raise;
  10192.     when others =>
  10193.       raise Unexpected_Error;
  10194.   end Read;
  10195.  
  10196.   -- ...................................................
  10197.   -- .                                                 .
  10198.   -- .  Binary_File.Write                              .  BODY
  10199.   -- .                                                 .
  10200.   -- ...................................................
  10201.   procedure Write (File : in FILE_TYPE;
  10202.                    Item : in BYTE) is
  10203.   --| Exceptions
  10204.   --|   Device_Error   -- raised if File cannot be accessed
  10205.   --|                  -- due to a hardware error
  10206.   --|   Mode_Error     -- raised if File is opened for
  10207.   --|                  -- input (mode IN_FILE)
  10208.   --|   Status_Error   -- raised if File has not been
  10209.   --|                  -- CREATEd
  10210.   --|
  10211.   --| Notes (none)
  10212.   begin -- Write
  10213.     BIO.Write (File.F, Item);
  10214.   exception
  10215.     when BIO.Device_Error =>
  10216.       raise Device_Error;
  10217.     when BIO.Mode_Error =>
  10218.       raise Mode_Error;
  10219.     when BIO.Status_Error =>
  10220.       raise Status_Error;
  10221.     when others =>
  10222.       raise Unexpected_Error;
  10223.   end Write;
  10224.  
  10225.   -- ...................................................
  10226.   -- .                                                 .
  10227.   -- .  Binary_File.Write                              .  BODY
  10228.   -- .                                                 .
  10229.   -- ...................................................
  10230.   procedure Write (File : in FILE_TYPE;
  10231.                    Item : in BLOCK) is
  10232.   --| Exceptions
  10233.   --|   Device_Error   -- raised if File cannot be accessed
  10234.   --|                  -- due to a hardware error
  10235.   --|   Mode_Error     -- raised if File is opened for
  10236.   --|                  -- input (mode IN_FILE)
  10237.   --|   Status_Error   -- raised if File has not been
  10238.   --|                  -- CREATEd
  10239.   --|
  10240.   --| Notes (none)
  10241.   begin -- Write
  10242.     for I in Item'First .. Item'Last loop
  10243.       BIO.Write (File.F, Item(I));
  10244.     end loop;
  10245.   exception
  10246.     when BIO.Device_Error =>
  10247.       raise Device_Error;
  10248.     when BIO.Mode_Error =>
  10249.       raise Mode_Error;
  10250.     when BIO.Status_Error =>
  10251.       raise Status_Error;
  10252.     when others =>
  10253.       raise Unexpected_Error;
  10254.   end Write;
  10255.  
  10256. end Binary_File;
  10257. --::::::::::
  10258. --bintree2.bdy
  10259. --::::::::::
  10260. with unchecked_deallocation;
  10261.  
  10262. package body Binarytrees is
  10263.  
  10264. ----------------------------------------------------------------------------
  10265. --                   Local Subprograms
  10266. ----------------------------------------------------------------------------
  10267.  
  10268. procedure Free is new unchecked_deallocation (Node, Tree);
  10269.  
  10270. function equal (X, Y: in ItemType) return boolean is 
  10271.  
  10272. begin
  10273.  
  10274.     return (not (X < Y))  and  (not (Y < X));
  10275. end;
  10276.  
  10277. ------------------------------------------------------------------------------
  10278.  
  10279. function generate (T :in Tree ) return  Nodeorder.List is
  10280.     L : Nodeorder.List;
  10281.  
  10282. --| This routine generates a list of pointers to nodes in the tree t.
  10283. --| The list is ordered with respect to the order of the nodes in the tree.
  10284.  
  10285. --| generate does a depth first search of the tree.  
  10286. --| 1.   It first visits the leftchild of t and generates the list for that.
  10287. --| 2.   It then appends the root node of t to the list generated for the left
  10288. --|      child.
  10289. --| 3.   It then appends the list generated for the rightchild to the list
  10290. --|      generated for the leftchild and the root.
  10291. --|
  10292.  
  10293. begin 
  10294.     L := NodeOrder.Create;
  10295.     if T /= null then
  10296.         L := Generate (T.Leftchild);
  10297.         Nodeorder.Attach (L, T);
  10298.         Nodeorder.Attach (L, Generate (T.Rightchild));
  10299.     end if;
  10300.     return L;
  10301. End Generate;
  10302.  
  10303. ------------------------------------------------------------------------------
  10304.  
  10305.  
  10306.  
  10307. ------------------------------------------------------------------------------
  10308. --                    Visible Subprograms
  10309. ------------------------------------------------------------------------------
  10310.  
  10311.  
  10312.  
  10313.  
  10314.  
  10315. ------------------------------------------------------------------------------
  10316.  
  10317. function Create  return Tree is
  10318.  
  10319. begin
  10320.     return null;
  10321. end;
  10322.  
  10323. -----------------------------------------------------------------------------
  10324.  
  10325. procedure Deposit (
  10326.           I :in      ItemType;
  10327.           S :in      Tree         ) is
  10328.  
  10329. begin
  10330.     S.Info := I;
  10331. end;
  10332.  
  10333. ------------------------------------------------------------------------------
  10334.  
  10335. procedure DestroyTree ( T :in out Tree) is
  10336.  
  10337. --| This procedure recursively destroys the tree T.
  10338. --|  1.  It destroy the leftchild of T
  10339. --|  2.  It then destroys the rightchild of T.
  10340. --|  3.  It then destroy the root T and set T to be null.
  10341.  
  10342. begin
  10343.     if T.leftchild /= null then
  10344.      DestroyTree (T.leftchild);
  10345.      DestroyTree (T.rightchild);
  10346.      Free (T);
  10347. end if;
  10348. end DestroyTree;
  10349.  
  10350. ------------------------------------------------------------------------------
  10351.  
  10352. procedure InsertNode ( 
  10353.         N           :in out ItemType;    --| Node being inserted.
  10354.         T           :in out Tree;        --| Tree node is being inserted
  10355.                                          --| into.                   
  10356.         Root        :   out Tree;        --| Root of the subtree which node N
  10357.                                          --| heads.  This is the position of 
  10358.                                          --| node N in T;
  10359.         Exists      :   out boolean      --| If this node already exists in
  10360.                                          --| the tree then Exists is true. If
  10361.                                          --| If this is the first insertion 
  10362.                                          --| Exists is false.
  10363.               
  10364.                                                                        ) is
  10365. --| This inserts the node N in T.
  10366. --| 1.  If T is null then a new node is allocated and assigned to T
  10367. --| 2.  If T is not null then T is searched for the proper place to insert n.
  10368. --|     This is first done by checking whether N < rightchild 
  10369. --| 3.  If this is not true then we check to see if leftchild < N
  10370. --| 4.  If this is not true then N is in the tree.
  10371.  
  10372. begin
  10373.     if T = null then
  10374.         T := new Node ' (Info => N, leftchild => null, rightchild => null);
  10375.         Root := T;
  10376.         Exists := false;
  10377.         N := T.Info;
  10378.     elsif N < T.Info then
  10379.         InsertNode (N, T.leftchild, Root, Exists);
  10380.     elsif T.Info < N then
  10381.         InsertNode (N, T.rightchild, Root, Exists);
  10382.     else
  10383.         Root := T;
  10384.         Exists := true;
  10385.         N := T.Info;
  10386.         
  10387.     end if;
  10388. end InsertNode;
  10389.  
  10390. ------------------------------------------------------------------------------
  10391.  
  10392. function MakeTreeIter (T :in     Tree ) return TreeIter is
  10393.  
  10394.     I :TreeIter;
  10395. --| This sets up the iterator for a tree T.
  10396. --| The NodeList keeps track of the order of the nodes of T.  The NodeList
  10397. --| is computed by first invoking Generate of the leftchild then append
  10398. --| the root node to NodeList and then append the result of Generate
  10399. --| to NodeList.  Since the tree is ordered such that 
  10400. --|
  10401. --|    leftchild < root    root < rightchild 
  10402. --| 
  10403. --| NodeOrder returns the nodes in ascending order.
  10404. --|
  10405. --| Thus NodeList keeps the list alive for the duration of the iteration
  10406. --| operation.  The variable State is the a pointer into the NodeList
  10407. --| which is the current place of the iteration.
  10408.  
  10409. begin
  10410.     I.NodeList := NodeOrder.Create;
  10411.     if T /= null then
  10412.         I.NodeList := Generate (T.leftchild);
  10413.         NodeOrder.Attach (I.NodeList, T);    
  10414.         NodeOrder.Attach (I.NodeList, Generate (T.rightChild));
  10415.     end if;
  10416.     I.State := NodeOrder.MakeListIter (I.NodeList);
  10417.     return I;    
  10418. end;    
  10419.  
  10420. ------------------------------------------------------------------------------
  10421.  
  10422. function More (I :in TreeIter) return boolean is
  10423.    
  10424. begin
  10425.     return NodeOrder.More (I.State);
  10426. end;
  10427.  
  10428. ------------------------------------------------------------------------------
  10429.  
  10430. procedure Next (
  10431.           I    :in out TreeIter;
  10432.           Info :   out ItemType       ) is
  10433.   T: Tree;
  10434.     
  10435. --| Next returns the information at the current position in the iterator
  10436. --| and increments the iterator.  This is accomplished by using the iterater
  10437. --| associated with the NodeOrder list.  This returns a pointer into the Tree
  10438. --| and then the information found at this node in T is returned.
  10439.  
  10440.  
  10441. begin
  10442.     NodeOrder.Next (I.State, T);
  10443.     Info := T.Info;
  10444. end;
  10445.  
  10446. -------------------------------------------------------------------------------
  10447.  
  10448. end BinaryTrees;
  10449.